Redis 生成电商系统商品全局唯一 ID
业务场景
在互联网电商系统中通常有着千亿级别的商品数据,万亿级别的订单数据;而传统的单库单表是无法支撑这种级别的数据的,通常会采用分库分表。
但是一旦进行分库分表,数据库表中原先设计的自增 ID 就会失去意义,所以在分布式系统中通常需要一个全局唯一 ID 来标识每一条数据。
全局唯一 ID 生成的技术方案有很多,业界比较有名的有
UUID
Redis
Snowflake
Leaf
实战演练
这里我们使用 Redis INCR 命令来实现分布式系统全局唯一 ID
核心 Maven Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
核心 application.properties
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.password=
spring.redis.timeout=2000
spring.redis.lettuce.pool.max-active=50
spring.redis.lettuce.pool.max-wait=2000
spring.redis.lettuce.pool.max-idle=10
spring.redis.lettuce.pool.min-idle=10
RedisConfiguration.java
package org.fool.springboot.config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
public class RedisConfiguration {
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
public CacheManager cacheManager(LettuceConnectionFactory connectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30L))
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory))
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
IdGeneratorService.java
package org.fool.springboot.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
public class IdGeneratorService {
private StringRedisTemplate stringRedisTemplate;
private static final String CACHE_MERCHANDISE_ID_KEY = "MERCHANDISE::ID";
public Long genId() {
return stringRedisTemplate.opsForValue().increment(CACHE_MERCHANDISE_ID_KEY);
}
}
MerchandiseRequest.java
package org.fool.springboot.contract.request;
import lombok.Data;
public class MerchandiseRequest {
private Long id;
private String name;
private Double price;
private String desc;
}
MerchandiseController.java
Test
多次执行以下 curl 命令
curl --location --request POST 'http://localhost:8080/merchandise/create' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Car",
"price": 300000.00,
"detail": "Lexus"
}'
泰克风格 只讲干货 不弄玄虚