众所周知,Redis(Remote Dictionary Server )是一个单实例单线程的、使用key-value存储系统的非关系型数据库,还能设置key的失效时间,所以用来实现流水编码(如订单号、人员编码)简直是再适合不过了。 网上已经有很多实现这个功能的教程了,不过基本全都是按照实现接口分离的形式开发的,比较复杂,有很多时候我们只是想在一个函数实现这个功能。下面就是我整理的一个方案,是在Spring Boot项目内实现的。
// 省略了import // 人员编号开头 private static final String SE_CODE_HEAD = "SE"; // 最大流水号 private static final Long MAX_SE_CODE = 9999L; // 一个月(31天)的小时数 private static final Long HOURS_IN_ONE_MONTH = 24*31L; // 必须使用StringRedisTemplate,不能使用RedisTemplate @Autowired public StringRedisTemplate redis; /** * 利用redis自增计数生成唯一人员编码 * @return */ public synchronized String generateSECode(){ // 流水号 Long suffix = 0L; // 前缀:SE + yy + MM SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyMM"); String prefix = SE_CODE_HEAD + simpleDateFormat.format(new Date()); // 如果该前缀已存在 if(redis.hasKey(prefix)) { suffix = redis.opsForValue().increment(prefix, 1L); if(suffix > MAX_SE_CODE) { throw new RuntimeException("软件工程师流水码已超过最大限制" + MAX_SE_CODE + ",请联系管理员"); } } // 如果该前缀不存在 else { try { redis.opsForValue().set(prefix, String.valueOf(suffix)); redis.expire(prefix, HOURS_IN_ONE_MONTH, TimeUnit.HOURS); } catch (Exception e) { throw new RuntimeException("软件工程师流水码写入REDIS时失败,请联系管理员"); } } return prefix + String.format("%04d", suffix); }