最近遇到一个问题在这里和大家分享一下:
目前在做仓库管理系统,在系统中遇到了很多的编号问题。如货件编号,入库编号,出库编号,清点编号,发货编号等等。这些编号都是按照相似的规则生成的,如货件编号就是"HJ"+8位日期数+4位随机数,入库编号就是“RK”+8位日期数+4位随机数。都是这样的规律。并且要求要具有唯一性。
在这样的情况下,雪花算法和uuid之类之前比较常用一些方法都无法使用了。
最开始想到的是利用加锁在实现:
//伪代码
加锁{
//1.获取日期
//2.获取随机数
//3.循环判随机数在数据库中是否重复,直到选择出一个不重复的数据
//4.添加编号到数据库
}
这种方式不需要别人来说,缺点就是非常的明显:效率低,不是个好的选择。
而且利用java中的锁,在分布式项目中就失效了。项目经理也在最开始的时候就说过,不推荐使用java中的锁。
所以现在的选在就只能是不使用java中已有的锁来提高上面代码的执行效率。而且分布式的锁在项目中一直没有使用,单独为了一个编号引入分布式锁有点小题大做了。
最后只能是采用数据库锁来实现这个功能。采用数据库中的排他锁来实现该功能。
首先在数据库中建立一张编号的表

然后采用往数据库中插入数据的方式,插入成功返回插入的数据。而且由于采用的数据库的锁,也会保障序号的唯一性。
代码放在下面:
/**
* 获取单号
* <p>
* 利用数据库的排它锁获取唯一的单号
* </p>
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public String getNo() {
Integer day = Integer.valueOf(LocalDate.now().format(formatter));
QueryWrapper<No> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(No::getDay, day);
queryWrapper.lambda().last("for update");
List<No> list = noService.list(queryWrapper);
No no = new No();
no.setDay(day);
no.setNo(list == null ? 1 : list.size() + 1);
noService.save(no);
return no.getDay() + "" + String.format("%05d",no.getNo());
}
这里事务的传递采用了REQUIRES_NEW策略,为了保障整个代码执行完成之后立刻提交事务,降低数据库锁,锁住的时间。
这里的问题说一下:8位日期数+4位随机数的这种方式,4位随机数一般来说是肯定不够使用的(这事项目经理的问题),但是项目目前还处于研发阶段,4位随机数完全够用,不够用时在扩充随机数的位数就好了。
还有一点想说的就是,数据库锁这种方式肯定不能在一些并发数高的项目中使用,我们这里目前只是小公司,这样使用是完全没有问题的。
在仓库管理系统中,面临各种编号(如货件、入库、出库等)的唯一性需求,不能使用雪花算法和uuid。作者分享了一种利用数据库排他锁实现编号生成的方法,避免使用Java锁和分布式锁,保证了在小规模并发情况下的效率和唯一性。代码示例展示了如何通过事务和数据库锁获取唯一的8位日期+4位随机数编号,同时指出此方案不适用于高并发场景,且未来可根据需求扩展随机数位数。
3661

被折叠的 条评论
为什么被折叠?



