Redis集群至少是3主3从节点,所以需要搭建Redis的6个节点。
通过Redis自增生成申请单号,解决并发问题生成申请单号相同问题,格式:年月日加上流水位数,生成并发下的唯一申请单号、订单号。
#Idgenerator 缓存数据库配置 Redis集群至少是3主3从节点,所以需要搭建Redis的6个节点
idgenerator.cluster.nodes = localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384,localhost:6385
idgenerator.cluster.password = 123456
idgenerator.preFixKey = DEMO:IDGENERATOR
idgenerator.maxRedirects = 3
idgenerator.soTimeout = 1000
idgenerator.timeout = 2000
idgenerator.masterName = mymaster
#最小空闲数
idgenerator.minIdle = 4
#最大空闲数
idgenerator.maxIdle = 16
#最大连接数
idgenerator.maxTotal = 256
#最大等待时间 单位毫秒(ms)
idgenerator.maxWaitMillis = 60000
#删除间隔
idgenerator.timeBetweenEvictionRunsMillis = -1
#使用连接时测试连接是否可用
idgenerator.testOnBorrow = true
idgenerator.testOnReturn = true
idgenerator.testOnCreate = true
#redis模式 single cluster sentinel
idgenerator.server = cluster
package com.demo.config;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
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.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.JedisPoolConfig;
/**
* Redis idgenerator 集群配置
*
* @author star
* @date 2023/04/20 10:54
**/
@Slf4j
@Configuration
@Data
public class LisIdgeneratorRedisClusterConfiguration implements Serializable {
@Value("${idgenerator.masterName:mymaster}")
private String masterName;
@Value("${idgenerator.cluster.password:\"\"}")
private String password;
@Value("${idgenerator.maxTotal:256}")
private int maxTotal;
@Value("${idgenerator.maxIdle:16}")
private int maxIdle;
@Value("${idgenerator.minIdle:4}")
private int minIdle;
@Value("${idgenerator.maxWaitMillis:10000}")
private int maxWaitMillis;
@Value("${idgenerator.cluster.nodes}")
private String redisClusterNotes;
@Value("${idgenerator.maxRedirects:3}")
private int maxRedirects;
@Value("${idgenerator.soTimeout:1000}")
private int soTimeout;
@Value("${idgenerator.timeout:2000}")
private int timeout;
@Value("${idgenerator.testOnBorrow:true}")
private boolean testOnBorrow;
@Value("${idgenerator.testOnReturn:true}")
private boolean testOnReturn;
@Value("${idgenerator.testOnCreate:true}")
private boolean testOnCreate;
@Value("${idgenerator.preFixKey:LIS:IDGENERATOR}")
private String preFixKey;
@Value("${idgenerator.server:cluster}")
private String server;
@Bean(name = "idgeneratorJedisPoolConfig")
public JedisPoolConfig getJedisPoolConfig(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
jedisPoolConfig.setTestOnReturn(testOnReturn);
jedisPoolConfig.setTestOnCreate(testOnCreate);
return jedisPoolConfig;
}
@Bean(name = "idgeneratorRedisClusterConfiguration")
public RedisClusterConfiguration getRedisClusterConfiguration(){
if(!"cluster".equals(server)){
return null;
}
if (StringUtils.isEmpty(redisClusterNotes)){
log.error("redis集群节点为空");
throw new RuntimeException();
}
String[] hostAndPorts = redisClusterNotes.split(",");
Set nodes = new HashSet<>();
for (String hostAndPort : hostAndPorts){
String[] ipAndPort = hostAndPort.split(":");
nodes.add(new RedisNode(ipAndPort[0],Integer.parseInt(ipAndPort[1])));
}
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
redisClusterConfiguration.setClusterNodes(nodes);
redisClusterConfiguration.setMaxRedirects(maxRedirects);
return redisClusterConfiguration;
}
@Bean(name = "idgeneratorRedisSentinelConfiguration")
public RedisSentinelConfiguration getRedisSentinelConfiguration(){
if(!"sentinel".equals(server)){
return null;
}
if (StringUtils.isEmpty(redisClusterNotes)){
log.error("redis哨兵节点为空");
throw new RuntimeException();
}
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
String[] hostAndPorts = redisClusterNotes.split(",");
for (String hostAndPort : hostAndPorts){
String[] ipAndPort = hostAndPort.split(":");
redisSentinelConfiguration.addSentinel(new RedisNode(ipAndPort[0],Integer.parseInt(ipAndPort[1])));
}
redisSentinelConfiguration.setMaster(masterName);
return redisSentinelConfiguration;
}
@Bean(name = "idgeneratorJedisConnectionFactory")
public JedisConnectionFactory jedisConnectionFactory(@Qualifier("idgeneratorJedisPoolConfig") JedisPoolConfig jedisPoolConfig) {
log.info("redis--idgenerator-{}模式",server);
if("single".equals(server)){
JedisConnectionFactory factory = new JedisConnectionFactory(jedisPoolConfig);
String[] hostAndPorts = redisClusterNotes.split(",");
Set nodes = new HashSet<>();
for (String hostAndPort : hostAndPorts){
String[] ipAndPort = hostAndPort.split(":");
nodes.add(new RedisNode(ipAndPort[0],Integer.parseInt(ipAndPort[1])));
}
factory.setHostName(nodes.iterator().next().getHost());
factory.setPort(nodes.iterator().next().getPort());
if(StringUtils.isNotBlank(password)){
factory.setPassword(password);
}
return factory;
}else if("sentinel".equals(server)){
RedisSentinelConfiguration redisSentinelConfiguration = getRedisSentinelConfiguration();
JedisConnectionFactory factory = new JedisConnectionFactory(redisSentinelConfiguration,jedisPoolConfig);
if(StringUtils.isNotBlank(password)){
factory.setPassword(password);
}
return factory;
}else if("cluster".equals(server)){
RedisClusterConfiguration redisClusterConfiguration1 = getRedisClusterConfiguration();
JedisConnectionFactory factory = new JedisConnectionFactory(redisClusterConfiguration1,jedisPoolConfig);
if(StringUtils.isNotBlank(password)){
factory.setPassword(password);
}
return factory;
}else {
log.error("redis配置错误");
throw new RuntimeException();
}
}
@Bean(name = "idgeneratorRedisTemplate")
public RedisTemplate redisTemplate(@Qualifier("idgeneratorJedisConnectionFactory") JedisConnectionFactory jedisConnectionFactory){
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
return redisTemplate;
}
public String getPreFixKey(String key){
return String.format("%s:%s",preFixKey,key);
}
}
package com.demo.idgenerator.redis;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import com.demo.config.LisIdgeneratorRedisClusterConfiguration;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException;
/**
* Cache Redis 缓存工具类
*
* @author star
* @date 2023/04/20 14:11
**/
@Slf4j
@Component
public class IdgeneratorRedisTool {
@Resource
LisIdgeneratorRedisClusterConfiguration idgeneratorConfig;
@Resource(name = "idgeneratorRedisTemplate")
private RedisTemplate redisTemplate;
/**
* 获取自增的ID
*/
public synchronized Long next(String key){
try {
long result = redisTemplate.opsForValue().increment(idgeneratorConfig.getPreFixKey(key),1);
return result;
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
} catch (JedisDataException e) {
log.error("JedisDataException",e);
}
return null;
}
/**
* 获取一个范围内的ID
* @param key 业务编码
* @param size 范围长度
* @return
*/
public synchronized List
@Resource
private IdgeneratorRedisTool idgeneratorRedisTool;
/**
* 通过Redis自增生成申请单号,解决并发问题生成申请单号相同问题,格式:年月日加上流水位数
* @param key 业务编号
* @param suffixNum 流水位数
* @return
*/
public String getMaxRequestNo(DemoDto dto) {
// 当天最大申请单号
Long maxRequestNo = 0L;
// 从redis中获取申请单号
maxRequestNo = idgeneratorRedisTool.nextRequestNo(Contrast.DEMO_SQID + ":"+dto.getJgid(), 2).longValue();
return maxRequestNo ;
}
输出今天申请单号:2023081801,生成2位申请单号的编号,从01开始。
输出明天申请单号:2023081901,生成2位申请单号的编号,从01开始。