Backend Development 11 min read

Implementing Sign‑in and Statistics with Redis BitMap in Spring Boot

This article explains how to implement a user sign‑in feature and its statistical analysis using Redis BitMap within a Spring Boot backend, covering basic BitMap commands, integration steps, core source code, continuous sign‑in calculation, and a bitmap‑based solution for cache penetration.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Implementing Sign‑in and Statistics with Redis BitMap in Spring Boot

1. Redis BitMap Basic Usage

BitMap Syntax and Commands

The article first compares a traditional MySQL table for storing sign‑in records with the memory‑efficient Redis BitMap approach, highlighting that each sign‑in can be represented by a single bit, reducing storage to a few bytes per user.

SETBIT : Set a bit at a given offset to 0 or 1.

GETBIT : Retrieve the bit value at a given offset.

BITCOUNT : Count the number of bits set to 1.

BITFIELD : Query, modify or increment values in a bit array.

BITFIELD_RO : Read bit array values in decimal.

BITOP : Perform bitwise operations (AND, OR, XOR) on multiple BitMaps.

BITPOS : Find the first occurrence of 0 or 1 within a range.

Implementing the Feature with BitMap

Using Redis 6.2, the article demonstrates the SETBIT, GETBIT, BITFIELD and BITPOS commands through screenshots, showing how to create a key, set a sign‑in bit, query its state, and retrieve bit fields.

2. Spring Boot Integration with Redis for Sign‑in

Requirement

Provide an API that records the current user's daily sign‑in status in Redis using a BitMap.

Design

The year‑month string is used as part of the Redis key, and the day of month determines the bit offset; setting the bit to 1 marks a successful sign‑in.

Core Source Code

UserController

@PostMapping("sign")
public Result sign() {
    return userService.sign();
}

UserServiceImpl

public Result sign() {
    // 1. Get logged‑in user
    Long userId = UserHolder.getUser().getId();
    // 2. Current date
    LocalDateTime now = LocalDateTime.now();
    // 3. Build key
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;
    // 4. Day of month
    int dayOfMonth = now.getDayOfMonth();
    // 5. Set bit to 1
    stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
    return Result.ok();
}

Testing

ApiFox is used to invoke the sign‑in endpoint, and Redis data is inspected to verify the bit has been set.

3. Sign‑in Statistics

Problem 1: Consecutive Sign‑in Days

The algorithm retrieves the last sign‑in of the current month and walks backwards until the first zero bit is encountered, counting the number of consecutive ones.

Problem 2: Retrieve All Sign‑in Data for the Current Month

BITFIELD key GET u[dayOfMonth] 0

This command returns a decimal number representing the bits for the days up to today; counting the number of 1 bits yields the total sign‑ins.

Problem 3: Iterate Bits Backwards

By repeatedly performing a bitwise AND with 1 and right‑shifting the number, each bit can be examined from the least‑significant side.

Core Source Code for Statistics

UserController

@GetMapping("/signCount")
public Result signCount() {
    return userService.signCount();
}

UserServiceImpl

public Result signCount() {
    // 1. Get user
    Long userId = UserHolder.getUser().getId();
    // 2. Current date
    LocalDateTime now = LocalDateTime.now();
    // 3. Build key
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;
    // 4. Day of month
    int dayOfMonth = now.getDayOfMonth();
    // 5. Get bitmap as decimal
    List
result = stringRedisTemplate.opsForValue().bitField(
        key,
        BitFieldSubCommands.create()
            .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
    if (result == null || result.isEmpty()) {
        return Result.ok(0);
    }
    Long num = result.get(0);
    if (num == null || num == 0) {
        return Result.ok(0);
    }
    int count = 0;
    while (true) {
        if ((num & 1) == 0) {
            break;
        } else {
            count++;
        }
        num >>>= 1;
    }
    return Result.ok(count);
}

4. Using BitMap to Mitigate Cache Penetration

The article proposes storing hashed IDs in a large BitMap instead of a list, allowing constant‑time existence checks while accepting a configurable false‑positive rate.

Conclusion

Redis BitMap combined with Spring Boot provides a lightweight, memory‑efficient solution for user sign‑in tracking and statistical analysis, and can also be leveraged to address cache‑penetration problems.

BackendRedisSpring BootBitmapCache PenetrationSign-in
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.