未提交的数据库事务和自动增加列

问题描述:

今天我遇到了一些好奇的行为,并想知道它是预期的还是标准的。我们对MySQL5使用Hibernate。在编码过程中,我忘记关闭交易,我想其他人可以联系。未提交的数据库事务和自动增加列

当我最后关闭事务时,运行代码并检查了表,我注意到以下内容。所有时间我错误地运行我的代码而没有关闭事务,因此没有导致实际的行被插入,但增加了自动增量代理主键值,这样我就有一个间隙(即没有行的id字段值为751至762)。

这是预期的还是标准的行为?可能会因数据库而异?和/或Hibernate自己的事务抽象对此有一些可能的影响吗?

+0

我知道答案,但这仍然是一个有趣的问题! – RichardOD 2009-09-09 14:22:48

+1

理想情况下,您的应用程序/设计不应受序列中任何空白的影响 - 您绝不应该陷入这种情况下 – 2009-09-09 15:28:24

是的,这是预期的。

如果你想一想:数据库还能做什么?如果增加列,然后在同一事务中的其他插入中将其用作外键,并且在您这样做时,其他人提交,那么他们将无法使用您的值。你会得到一个差距。

像Oracle这样的数据库中的序列的工作方式大致相同。一旦请求了特定的值,它是否被提交并不重要。它永远不会被重用。序列也不是绝对有序的。

这是非常期待的行为。如果没有,数据库将不得不等待每个已经插入记录的事务完成,然后将新的ID分配给下一个插入。

是的,这是预期的行为。 This documentation解释得非常好。

从5.1.22开始,实际上有三种不同的锁定模式来控制并发事务如何获得自动增量值。但是这三者都会导致回滚事务的空隙(回滚事务所使用的自动增量值将被丢弃)。

数据库序列不保证没有间隙的id序列。它们被设计成独立于事务,只有在这种方式下才可以是非阻塞的。

你想要没有差距,你必须编写自己的存储过程来事务性地增加列,但是这样的代码会阻塞其他事务,所以你必须是carrefull。

你做SELECT CURRVAL FROM SEQUENCE_TABLE WHERE TYPE =:YOUR_SEQ_NAME FOR UPDATE; UPDATE SEQUENCE_TABLE SET CURRVAL =:INCREMENTED_CURRVAL WHERE TYPE =:YOUR_SEQ。