springBoot使用redis获取自增序号
获取自增序号springBoot使用redis获取自增序号pom文件参考代码java代码lua脚本测试代码配置springBoot使用redis获取自增序号spring boot 集成 redis clientpom文件<parent><artifactId>spring-boot-starter-parent</artifactId><groupId&g
·
springBoot使用redis获取自增序号
spring boot 集成 redis client
pom文件
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuce.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.5.0</version>
</dependency>
参考代码
配置
spring:
redis:
cluster:
nodes: ip:port
max-redirects: 3
redis:
timeout: 10000 #客户端超时时间单位是毫秒 默认是2000
maxIdle: 300 #最大空闲数
maxTotal: 1000 #控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
maxWaitMillis: 1000 #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
minEvictableIdleTimeMillis: 300000 #连接的最小空闲时间 默认1800000毫秒(30分钟)
numTestsPerEvictionRun: 1024 #每次释放连接的最大数目,默认3
timeBetweenEvictionRunsMillis: 30000 #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
testOnBorrow: true #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
testWhileIdle: true #在空闲时检查有效性, 默认false
#password: 123456 #密码
password:
dataBase: 0
配置类代码
package cn.项目路径.config;
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
/** redis 配置
* @author tk
* @date 2020/11/3 9:58
*/
@Configuration
public class RedisConfig {
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
@Value("${spring.redis.cluster.max-redirects}")
private Integer maxRedirects;
@Value("${redis.password}")
private String password;
@Value("${redis.timeout}")
private Integer timeout;
@Value("${redis.maxIdle}")
private Integer maxIdle;
@Value("${redis.maxTotal}")
private Integer maxTotal;
@Value("${redis.maxWaitMillis}")
private Integer maxWaitMillis;
@Value("${redis.minEvictableIdleTimeMillis}")
private Integer minEvictableIdleTimeMillis;
@Value("${redis.numTestsPerEvictionRun}")
private Integer numTestsPerEvictionRun;
@Value("${redis.timeBetweenEvictionRunsMillis}")
private Integer timeBetweenEvictionRunsMillis;
@Value("${redis.testOnBorrow}")
private boolean testOnBorrow;
@Value("${redis.testWhileIdle}")
private boolean testWhileIdle;
@Value("${redis.dataBase}")
private Integer dataBase;
/** Redis集群的配置 */
@Bean
public RedisClusterConfiguration redisClusterConfiguration(){
if(!clusterNodes.contains(",")) {
return null;
}
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
//Set<RedisNode> clusterNodes
String[] serverArray = clusterNodes.split(",");
Set<RedisNode> nodes = new HashSet<RedisNode>();
for (String ipPort : serverArray) {
String[] ipAndPort = ipPort.split(":");
nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
}
redisClusterConfiguration.setClusterNodes(nodes);
redisClusterConfiguration.setMaxRedirects(maxRedirects);
redisClusterConfiguration.setPassword(RedisPassword.of(password));
return redisClusterConfiguration;
}
/** 集群redis 使用Lettuce集群模式 */
@Bean
public LettuceConnectionFactory lettuceConnectionFactory() {
// 连接池配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxWaitMillis(maxWaitMillis);
LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
.commandTimeout(Duration.ofMillis(timeout))
.shutdownTimeout(Duration.ofMillis(timeout))
.poolConfig(poolConfig)
.build();
LettuceConnectionFactory lettuceConnectionFactory = null;
RedisClusterConfiguration redisClusterConfiguration = redisClusterConfiguration();
/** 集群redis */
if (redisClusterConfiguration != null) {
lettuceConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}else{
/* 单机redis模式 */
RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(clusterNodes.split(":")[0],Integer.valueOf(clusterNodes.split(":")[1]));
standaloneConfiguration.setPassword(password);
lettuceConnectionFactory = new LettuceConnectionFactory(standaloneConfiguration, lettuceClientConfiguration);
}
lettuceConnectionFactory.setDatabase(dataBase);
return lettuceConnectionFactory;
}
/** 实例化 RedisTemplate 对象 */
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate);
return redisTemplate;
}
/** 设置数据存入 redis 的序列化方式,并开启事务
* 使用默认的序列化会导致key乱码 */
private void initDomainRedisTemplate(RedisTemplate <String, Object> redisTemplate) {
//如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!
redisTemplate.setKeySerializer(new StringRedisSerializer());
//这个地方有一个问题,这种序列化器会将value序列化成对象存储进redis中,如果
//你想取出value,然后进行自增的话,这种序列化器是不可以的,因为对象不能自增;
//需要改成StringRedisSerializer序列化器。
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setEnableTransactionSupport(false);
/** lettuce 集群模式 */
redisTemplate.setConnectionFactory(lettuceConnectionFactory());
redisTemplate.afterPropertiesSet();
}
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
@Bean
public CookieSerializer httpSessionIdResolver(){
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setUseHttpOnlyCookie(false);
cookieSerializer.setSameSite(null);
return cookieSerializer;
}
}
使用代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class IDUtil {
private final RedisTemplate<String, String> redisTemplate;
@Autowired
public IDUtil(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public String genNo(){
DefaultRedisScript script = new DefaultRedisScript<>();
script.setResultType(Long.class);
script.setScriptSource(new ResourceScriptSource(new ClassPathResource("id.lua")));
List<String> key = new ArrayList<>(1);
key.add("genid");
Object result = redisTemplate.execute(script, key, "1", "9999");
return result.toString();
}
}
lua脚本
local curr = redis.call('GET',KEYS[1]);
if( curr == false) then
redis.call('SET',KEYS[1],0)
elseif curr and tonumber(curr) >= tonumber(ARGV[2]) then
redis.call('SET',KEYS[1],0)
return 0
else
redis.call('incrby',keys[1],ARGV[1])
return curr + ARGV[1]
end
测试代码
配置
spring:
redis:
host: localhost
port: 6379
password:
database: 0
timeout: 10000ms
lettuce:
pool:
max-active: 50
max-wait: -1
max-idle: 8
配置类代码
package cn.**.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* RedisConfig 类说明:
*
* @author z.y
* @version v1.0
* @date 2021/10/26
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// key 使用 字符串序列化
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
template.setEnableTransactionSupport(false);
template.setHashKeySerializer(new StringRedisSerializer());
valueSerializer(template);
// 其余 属性 使用默认设置
template.afterPropertiesSet();
return template;
}
private void valueSerializer(RedisTemplate<String, Object> template){
// 对象 使用 json 序列化
Jackson2JsonRedisSerializer<?> jrs = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jrs.setObjectMapper(mapper);
template.setHashValueSerializer(jrs);
}
}
使用代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class RedisCommon{
private final RedisTemplate<String, Object> redisTemplate;
private ValueOperations<String, Object> ops;
private DefaultRedisScript<Long> script;
@Autowired
public RedisCommon(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
ops = redisTemplate.opsForValue();
script = new DefaultRedisScript<>();
script.setResultType(Long.class);
script.setScriptSource(new ResourceScriptSource(new ClassPathResource("id.lua")));
}
/** 使用 redis 生成 序号
* @param endKey 后缀key
* @param max 序号最大值
* @param expire 存活时长
* @return 序号
*/
public Long genNo(String endKey,String max,String expire){
List<String> key = new ArrayList<>(1);
key.add("CN:ZY:GEN:"+endKey);
return redisTemplate.execute(script, key, "1", max ,expire);
}
public Long genNo(String key){
return genNo(key,"999999","86400");
}
}
lua脚本
local curr = redis.call('GET',KEYS[1]);
if( curr == false) then
redis.call('SET',KEYS[1],0)
if ( ARGV[3] ~= nil) then
redis.call('EXPIRE',KEYS[1],ARGV[3])
end
return 0
elseif curr and tonumber(curr) >= tonumber(ARGV[2]) then
redis.call('SET',KEYS[1],0)
if ( ARGV[3] ~= nil) then
redis.call('EXPIRE',KEYS[1],ARGV[3])
end
return 0
else
redis.call('INCRBY',keys[1],ARGV[1])
return curr + ARGV[1]
end
lua脚本2
local curr = redis.call('GET',KEYS[1]);
if( curr == false or (curr and tonumber(curr) >= tonumber(ARGV[2])) ) then
redis.call('SET',KEYS[1],0)
if ( ARGV[3] ~= nil) then
redis.call('EXPIRE',KEYS[1],ARGV[3])
end
return 0
else
return redis.call('INCRBY',keys[1],ARGV[1])
end
输出
另一种方式实现
这种方式 不用写 lua脚本,更简洁
spring boot整合redisTemplate获取自增主键incr
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisCommon{
private final RedisTemplate<String, Object> redisTemplate;
@Autowired
public RedisCommon(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public Long genNo2(String endKey, long liveTime){
RedisAtomicLong ral = new RedisAtomicLong("CN:ZY:GEN:"+endKey, redisTemplate.getConnectionFactory());
long l = ral.getAndIncrement();
if ( ral.longValue() <= 1 && liveTime > 0) {
ral.expire(liveTime, TimeUnit.SECONDS);
}
return l;
}
}
输出
0
1
2
end
更多推荐
已为社区贡献5条内容
所有评论(0)