| | |
| | | private static final String BAG_NO_SEQ_KEY = "mes:bag_no:seq"; |
| | | |
| | | /** |
| | | * 生产批次流水号自增 KEY 前缀(按年份隔离) |
| | | */ |
| | | private static final String BATCH_NO_SEQ_KEY_PREFIX = "mes:pro_batch_code:seq:"; |
| | | |
| | | /** |
| | | * 单次批量取码的最大个数 |
| | | * <p> |
| | | * 受 Redis 单条命令参数规模与响应体大小约束,过大反而增加单次阻塞时间。 |
| | |
| | | + "local base = tonumber(ARGV[2]) " |
| | | + "if (not cur) or (tonumber(cur) < base) then redis.call('SET', KEYS[1], base) end " |
| | | + "return redis.call('INCRBY', KEYS[1], ARGV[1])", |
| | | Long.class); |
| | | |
| | | /** |
| | | * 原子分配生产批次流水号:先按库内当前最大流水校正基准值,再自增。 |
| | | * 手动录入较大批次号或直接导入数据后,下一次自动取号不会与之重复。 |
| | | */ |
| | | private static final RedisScript<Long> ALLOCATE_BATCH_NO_SCRIPT = new DefaultRedisScript<>( |
| | | "local cur = redis.call('GET', KEYS[1]) " |
| | | + "local base = tonumber(ARGV[1]) " |
| | | + "if (not cur) or (tonumber(cur) < base) then redis.call('SET', KEYS[1], base) end " |
| | | + "return redis.call('INCR', KEYS[1])", |
| | | Long.class); |
| | | |
| | | @Resource |
| | |
| | | } |
| | | |
| | | /** |
| | | * 原子分配生产批次流水号:先按库内当前最大流水校正基准值,再自增。 |
| | | * |
| | | * @param year 批次号年份(4 位) |
| | | * @param dbMaxSerial 数据库当年已用最大流水号,传 null 视为 0 |
| | | * @return 下一个流水号 |
| | | */ |
| | | public int allocateBatchNo(String year, Integer dbMaxSerial) { |
| | | Long next = stringRedisTemplate.execute(ALLOCATE_BATCH_NO_SCRIPT, |
| | | List.of(BATCH_NO_SEQ_KEY_PREFIX + year), |
| | | String.valueOf(dbMaxSerial == null ? 0 : dbMaxSerial)); |
| | | if (next == null) { |
| | | throw new IllegalStateException("分配生产批次流水号失败,请重试"); |
| | | } |
| | | return next.intValue(); |
| | | } |
| | | |
| | | /** |
| | | * 原子分配一段连续的袋序号,返回区间起始值。 |
| | | * <p> |
| | | * 袋序号原先由「查库内最大值再 +1」得到,并发生成时两个请求会读到同一个最大值, |