How to use redis to generate serial number
Summary
This article describes how to use redis to generate serial numbers. This article is implemented in spring boot. After knowing the principle, other frameworks can be easily implemented.
Principle introduction
This paper mainly uses the incr method of redis to supplement zero. Then the unique serial number is composed of time, random number and prefix.
Here is the structure of the serial number.
At the end of this article, I will briefly introduce the persistence of redis. Prevent redis downtime from causing auto increment reset. As a result, the serial number is repeated.
Flow chart
This implementation is divided into
1. Initializing serial number information into cache
2. Generate serial number
Here is the general flow chart of each
1. Initializing serial number information into cache
2. Generate serial number
code implementation
1. Serial number entity class
Used to store serial number information
@Data public class YuSnGenCode { // The serial number generates the dependent class. The class name will be used as the key of redis private Class entity; // prefix private String prefix; // If the number of self increasing digits does not reach this digit, it will be automatically zeroed private Integer num; public YuSnGenCode(Class entity, String prefix, Integer num) { this.entity = entity; this.prefix = prefix; this.num = num; } }
2. Initialize serial number into cache
Initializing the serial number after program startup
@Component @Slf4j public class YuSnGenStart implements ApplicationRunner { @Autowired YuSnGenUtil yuSnGenUtil; @Override public void run(ApplicationArguments args) throws Exception { log.info("=====Start initializing serial number====="); List<YuSnGenCode> yuSnGenCodeList = new ArrayList<>(); yuSnGenCodeList.add(new YuSnGenCode(Account.class, "AC", 6)); yuSnGenCodeList.add(new YuSnGenCode(Shop.class, "DP", 6)); yuSnGenCodeList.add(new YuSnGenCode(Order.class, "OR", 6)); yuSnGenCodeList.add(new YuSnGenCode(Dispatch.class, "DL", 6)); yuSnGenCodeList.add(new YuSnGenCode(Refund.class, "RF", 6)); yuSnGenCodeList.add(new YuSnGenCode(PayLog.class, "PL", 6)); yuSnGenCodeList.add(new YuSnGenCode(Withdrawal.class, "WR", 6)); yuSnGenCodeList.add(new YuSnGenCode(Aftermarket.class, "AS", 6)); yuSnGenCodeList.add(new YuSnGenCode(Coupon.class, "CO", 6)); yuSnGenCodeList.add(new YuSnGenCode(CouponGen.class, "CG", 10)); yuSnGenCodeList.add(new YuSnGenCode(Draw.class, "DP", 6)); yuSnGenUtil.init(yuSnGenCodeList); log.info("=====Initialization of serial number completed====="); } }
public void init(List<YuSnGenCode> yuSnGenCodes) { // Serial number initialization into cache for (YuSnGenCode yuSnGenCode : yuSnGenCodes) { String redisKey = yuSnGenCode.getEntity().getName(); // Cache key: key: entity class name value: serial number data (prefix, self incrementing digits) redisTemplate.opsForValue().set(yuSnGenCode.getEntity().getName(), FastJsonUtils.toJsonStr(yuSnGenCode)); log.info(yuSnGenCode.getEntity().getName() + "Initialized"); } }
The serial number after initialization is shown in the figure below
3. Generate serial number
public Optional<String> gen(Class c) { // Get the name of the entity class String redisKey = c.getName(); // Determine whether this entity class has been initialized if (null != redisTemplate.opsForValue().get(redisKey)) { // Get the generation information of serial number from cache YuSnGenCode yuSnGenCode = FastJsonUtils.toBean(redisTemplate.opsForValue().get(redisKey).toString(), YuSnGenCode.class); // According to the prefix of the serial number, judge whether the serial number has been generated today if (redisTemplate.opsForValue().get(yuSnGenCode.getPrefix()) == null) { // If not, create a new cache format (key: or value: 0) // Set to expire at 00:00:01 the next morning Long todayTime = LocalDate.now().plusDays(1).atTime(0, 0, 0, 1).atOffset(ZoneOffset.ofHours(8)).toEpochSecond(); Long nowTime = LocalDateTime.now().atOffset(ZoneOffset.ofHours(8)).toEpochSecond(); Long expireTime = todayTime - nowTime; redisTemplate.opsForValue().set(yuSnGenCode.getPrefix(), 0, expireTime*1000, TimeUnit.MILLISECONDS); } // Carry out auto increment operation StringBuffer sn = new StringBuffer(); // Combined with prefix, time and random number sn.append(yuSnGenCode.getPrefix()); String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); sn.append(date); Long num = redisTemplate.opsForValue().increment(yuSnGenCode.getPrefix()); sn.append(addZero(String.valueOf(num), yuSnGenCode.getNum())); String random = String.valueOf(new Random().nextInt(1000)); sn.append(random); // Generate final serial number return return Optional.ofNullable(sn.toString()); } return Optional.ofNullable(null); }
// Automatic zeros public String addZero(String numStr, Integer maxNum) { int addNum = maxNum - numStr.length(); StringBuffer rStr = new StringBuffer(); for (int i = 0; i < addNum; i++) { rStr.append("0"); } rStr.append(numStr); return rStr.toString(); }
After the first generation of the serial number, there will be a data in redis with the prefix of the serial number as the key, and then it will be added directly. No need to add
Code testing
General test
public Response test2() { return Response.success(yuSnGenUtil.gen(Order.class).get()); }
give the result as follows
Concurrent test
Here we use ab for stress concurrency testing
Before the test, our serial number data is 0
Conduct 5000 request 100 concurrent test
There is no problem that the serial number data is 5000 after the request.
redis persistence
Redis persistence means that data can still be recovered after a restart after an unexpected exit of redis. We use redis persistence here to prevent redis from accidentally exiting and restarting, resulting in the reset of serial number data, resulting in the generation of duplicate serial number.
Redis provides different levels of persistence:
RDB
RDB persistence can store your data in a snapshot at a specified time interval
AOF
AOF persistent mode records every write operation to the server. When the server is restarted, these commands will be executed again to recover the original data
We are using AOF this time
According to the tips on the official website. We just need to open appendonly in the redis.config file. In this way, redis will generate the appendonly.aof file. When the server restarts, it will execute these commands again to recover the original data.
Be careful
Because there are three default backup methods for AOF
1. always executes fsync every time a new command is appended to an AOF file: very slow and very secure
2. Every sec fsync once per second: fast enough (similar to using RDB persistence), and only one second of data will be lost in case of failure.
3. no never fsync: hands over the data to the operating system for processing. Faster and less secure options.
And we use the second. It is also the default of AOF. But in this way, the data of 1s may be lost in case of failure, so if the data requirements are very strict, students can use the first method to only modify the appendfsync attribute of redis.config file.
The above is how to use the incr auto increment method of redis to write and generate serial numbers. If you have any questions, please point out in the comment area. Thank you A kind of