Oracle Sequence使用注意
情况大概是这样:项目中使用Oracle的Sequence来生成流水号,并设置cache为20,。然后通过测试环节后交付给客户上生产。然后一段时间后,客户反馈说有bug。拿到生产环境的数据库dump部署后一查,发现相关数据确实有问题:
1)如果按照流水号从小到大,数据入库时间不连续,并且流水号跳号,比如从1000、1001直接到1020,中间丢了1002~1019。
2)如果按照数据入库时间从小到大,流水号跳号并且是穿插,比如从1000、1001直接到1020,然后是1002,、1003、然后是1021。
通过查找资料以及结合生产环境的Oracle使用RAC推断,上面的2)才是数据入库的方式:
RAC有2个节点,节点1和节点2。假设某个表的Sequence从1000开始,cache20个。一开始请求从节点1拿流水号,使得节点1缓存20个流水号(1000~1019),在使用了1000、1001之后,请求被切到节点2,然后节点2也缓存20个流水号(1020~1039),在使用了1020之后请求再被切回节点1,继续使用接下来的1002和1003,再切回节点2使用1021。如此造成流水号穿插跳号情形。因此如果我们的sql里面对流水号有一些max,min,>=、<=等等类型的操作,那么可能就会有问题。
相关Oracle资料也介绍,Sequence只能保证唯一,不能保证连续(即可能跳号,比如share_pool被刷或宕机后,原cache的流水号将丢失。还有就是事务回滚也会导致流水号跳号)。
而我这里遇到的场景要特殊,是穿插跳号,而不是单向跳号,情况更严重。
解决:
1)对于业务流水号(就是那种需要显示出来给客户看的,比如XXX编码),并且要求严格连续而且唯一的那种,还是自定义流水号生成器吧。
2)如果只是数据流水号,可以修改Sequence为nocache,这样能保证单向唯一,但还不能保证连续(因为事务回滚)。我们就是采取这种方式,因为底层sql大部分都是采用Sequence,如果全部改掉,工作量大,何况已上生产,采用折中方案。如果是处于开发阶段,可以考虑全部采用1)中说的自定义流水号生成器。
总结:
Q:为什么问题到了生产才出现?
A:
--我们在测试环节并没有真正完全模拟生产环境,没有部署RAC。
--对Sequence,前期基本就是知道怎么用,而没有真正去了解过使用的注意事项。
记录下来,避免重复踩到一个坑里面。