序列不在oracle表的一行中



我有一个项目,它的结构是java ee 7。我使用hibernate作为ORM,我的数据库是Oracle。

我使用@SequenceGenerator与allocationSize = 1为我的实体和@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")的id。我的数据库序列在Oracle有缓存=1000。但是,当我在数据库中持久化两条记录时,即使在一天之后,第一条记录的id也比第二条记录老,并且id不是连续的。

我如何解决这个问题,我的问题是什么?

由于您正在使用11g(一个非常旧的版本,因此您的公司应该考虑尽快升级),因此RAC选项必须在性能和完整性之间取得平衡。

你有两个选项noordervsorder

create sequence xxx start with 1 increment by 1 noorder|order cache xxx

实例如何协调它们对序列值的使用并避免两个实例使用相同值的风险?

有两种解决方案:默认的noorder机制,每个实例的行为就好像它不知道其他实例的存在。另一个是order选项,其中实例通过使用全局队列不断协商,以确定在任何时刻哪个实例应该负责该序列。

Noorder

这种无顺序机制的结果是,每个实例将通过不同范围的数字工作,并且实例之间不会有重叠。如果会话每秒登录到数据库一次,发出对nextval的调用(每次都通过不同的实例进行连接),那么返回的值似乎是相当随机地分散在由"实例数x缓存大小"决定的范围内。唯一性将得到保证,但顺序将得不到保证。

如果你用order选项声明一个序列,Oracle会采用一个策略,为这些值使用一个"缓存",并引入一种机制来确保一次只有一个实例可以访问和修改该缓存。Oracle通过利用其Global Enqueue服务实现了这一点。每当会话发出对nextval的调用时,实例就会在序列缓存上获得独占的SV锁(全局队列),这实际上是在说,"谁获得了关于这个序列的最新信息——我想要控制"。在独占模式下持有SV锁的实例是唯一可以增加缓存值的实例,并且在必要时通过增加高水位来更新seq$表。这意味着序列号将再次按顺序生成。但是这个选项在性能上有损失,应该仔细考虑。

总结如果你的事务是快速的,你可以使用order并测试它的行为。如果你的交易速度不快,我会一起避免使用order。最好的选择是升级到19c (12c已经接近过时),并使用IDENTTTY COLUMNS

如果在每个节点上有无序的(单独的)缓存(默认):

node 1: cache values (1 - 1000)
node 2: cache values (1001 - 2000)

则缓存不能重叠值,所使用的值将取决于执行插入的节点。这就是为什么你的序列值目前看起来是乱序的。

使用NOCACHE和/或ORDERED选项将得到顺序的数字,但是您可以预期至少会对应用程序产生一些性能影响,因为数据库必须执行更多的开销来确定当前的序列值,然后才能将其提供给SQL命令。如果执行大量插入操作(当前缓存值为1000),减小缓存大小或完全消除缓存可能会对性能产生严重的负面影响。

假设现在您继续使用缓存(无论是否有序),请注意每次重新启动数据库或节点(取决于您的确切配置)时,未使用的缓存值将被刷新和丢失,并将创建一个新的缓存。

最后,重要的是要认识到,序列值并不打算(对于大多数应用程序)是完全连续的,没有间隙,甚至(在您的情况下)是有序的。它们是唯一的,旨在唯一的。一定要理解您的需求,如果序列的行为不完全像您期望的那样,不要推迟:值必须按照插入的顺序顺序排列,序列中的间隙会影响您的应用程序吗?如果答案是不是,应用程序不会在意,那么为了性能起见,继续使用已有的内容。

最新更新