根据redis生成流水号主键

       这段时间因为工作的关系,研究了一下流水号这一块业务处理,很多时候主键使用相应的流水号,还挺不错的,流水号同样也适用于分布式系统,这里直接上代码,边上代码,边写注释把

       因为我负责的系统是很久以前的了,用的还是Springmvc+JPA的架构,所以这里引用的maven jar包会比较旧,用cloud的同学可以使用 新的jar包

		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
		</dependency>

   接下来是spring配置,放在applicationContext.xml下面

  


	<!-- Redis 配置 -->
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="${redis.maxActive}"/>
		<property name="maxIdle" value="${redis.maxIdle}"/>
		<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
		<property name="testOnBorrow" value="true"/>
	</bean>

	<!-- redis单节点数据库连接配置 -->
	<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="hostName" value="${redis.host}"/>
		<property name="port" value="${redis.port}"/>
		<property name="password" value="${redis.password}"/>
		<property name="poolConfig" ref="jedisPoolConfig"/>
	</bean>

	<!-- redisTemplate配置 -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory" ref="jedisConnectionFactory"/>
		<property name="keySerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
		</property>
		<property name="valueSerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
		</property>
		<property name="hashKeySerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="hashValueSerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
	</bean>

    注意一点: keySerializer 和valueSerializer 以及下面那两个,这里配置是解决乱码的问题,redis客户端连上去能看到正常的数据

   redis配置好了,我们来说一下要达到的流水号要求    ----  XJ202011051000,XJ202011051001,XJ202011051002,XJ202011051003

   不难看出后面的4位位数都是逐个递增的,我考虑到并发量高的原因,为了不影响主键生成带来系统压力,所以才选择redis这一块,redis的数值自增可以帮我们很好的解决这个问题

   

@Component
public class RedisUtils {

    private static final int POOLINDEX = 1;

    private static final int defaultInitValue = 1000;

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;


    public void setValue(String key, Integer value) {
        JedisConnectionFactory connectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
        connectionFactory.setDatabase(POOLINDEX);
        redisTemplate.opsForValue().set(key, value);
    }

    public void setValue(String key, Integer value, long timeout, TimeUnit unit) {
        JedisConnectionFactory connectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
        connectionFactory.setDatabase(POOLINDEX);
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    public Object getValue(Object key) {
        JedisConnectionFactory connectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
        connectionFactory.setDatabase(POOLINDEX);
        Object value = redisTemplate.opsForValue().get(key);
        return value;
    }

    public Long getIncrementNum(String key) {
        JedisConnectionFactory connectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
        connectionFactory.setDatabase(POOLINDEX);
        if (getValue(key) != null) {
            RedisAtomicLong enquiryRedisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
            return enquiryRedisAtomicLong.incrementAndGet();
        } else {
            RedisAtomicLong enquiryRedisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory(), defaultInitValue);
            return enquiryRedisAtomicLong.incrementAndGet();
        }

    }
}

这里要注意一点,如果redis里面不存在那个键的话,默认从1000开始自增,getIncrementNum就是获取自增的方法。

public class IncreatementIdUtils implements Serializable {

    @Inject
    private RedisUtils redisUtils;

    public String getComposeId(String prefix) {
        LocalDateTime now = LocalDateTime.now();
        Long incrementNum = redisUtils.getIncrementNum(ProductEnquiry.REDIS_KEY);
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        String format = dtf.format(now);
        return prefix + format + incrementNum;
    }

    
}

这是主键生成的工具类,引用redisUtil,生成组合型流水号主键

测试类和效果

    @GetMapping("/testRedisKey")
    @ResponseBody
    public String testRedisKey(){
        return increatementIdUtils.getComposeId("XJ");
    }

 

但是代码其实还能写的再优雅一点,后面来优化一下,这里还有个很疑惑的问题

既然是以来于redis,那就要考虑一下redis宕机怎么办,现在的架构,如果redis宕机,主键生成就失败了,如果是分布式条件下,大概率会被熔断器截掉

而且流水号不能丢失,我的想法是由两个,一个是配置redis持久化,及时重启了,也能够恢复这个流水号数据,还有一个方案是存入数据库中。但是怎么

存入数据库中,确保数据库不会被高并发压垮,这也是一个值得深思的问题,如果有大神知道的话,就相互交流一下哈

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值