- springBoot使用redis获取自增序号
- pom文件
- 参考代码
- 配置
- 配置类代码
- 使用代码
- lua脚本
- 测试代码
- 配置
- 配置类代码
- 使用代码
- lua脚本
- lua脚本2
- 输出
- end
pom文件spring boot 集成 redis client
参考代码 配置spring-boot-starter-parent org.springframework.boot 2.1.6.RELEASE 1.8 UTF-8 UTF-8 2.1.6.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.session spring-session-data-redis ${spring-boot.version} io.lettuce lettuce-core ${lettuce.version} org.apache.commons commons-pool2 2.5.0
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;
@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;
@Bean
public RedisClusterConfiguration redisClusterConfiguration(){
if(!clusterNodes.contains(",")) {
return null;
}
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
//Set clusterNodes
String[] serverArray = clusterNodes.split(",");
Set nodes = new HashSet();
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;
}
@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();
if (redisClusterConfiguration != null) {
lettuceConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}else{
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;
}
@Bean
public RedisTemplate redisTemplate() {
RedisTemplate redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate);
return redisTemplate;
}
private void initDomainRedisTemplate(RedisTemplate 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);
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 redisTemplate;
@Autowired
public IDUtil(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public String genNo(){
DefaultRedisscript script = new DefaultRedisscript<>();
script.setResultType(Long.class);
script.setscriptSource(new ResourcescriptSource(new ClassPathResource("id.lua")));
List 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;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
RedisTemplate 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 template){
// 对象 使用 json 序列化
Jackson2JsonRedisSerializer> jrs = new Jackson2JsonRedisSerializer
使用代码
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 redisTemplate;
private ValueOperations ops;
private DefaultRedisscript script;
@Autowired
public RedisCommon(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
ops = redisTemplate.opsForValue();
script = new DefaultRedisscript<>();
script.setResultType(Long.class);
script.setscriptSource(new ResourcescriptSource(new ClassPathResource("id.lua")));
}
public Long genNo(String endKey,String max,String expire){
List 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
输出
end


