RepeatableRead似乎没有锁定读取

时间:2011-03-18 14:30:28

标签: c# ado.net transactions sql-server-2008-r2

我遇到了一个奇怪的问题。我有一个表具有在INSTEAD OF触发器中生成的主键。这可能是实现主键的最糟糕方式,但它们基本上获取最大值,将其递增1,并使用此值作为键。这发生在而不是触发器中。

我有一个启动RepeatableRead事务的.Net应用程序,我在此表中插入一条记录。只要我不尝试同时执行多个插入,这样就可以正常工作。如果我这样做,我会收到PK违规错误。在我看来,插入都被触发,触发器为每个事务获取相同的最后一个数字,将其递增1,然后尝试插入具有相同新“标识符”的两个记录。

我已经告诉DBA设置此触发器,并且他认为RepeatableRead应该阻止这种情况发生,因为它显然锁定了表以进行读取,而其他事务将等待锁被释放。所以,从本质上讲,我的交易将以串行方式进行。

所以,问题是,如果RepeatableRead以DBA描述的方式工作,为什么我会得到PK违规?

2 个答案:

答案 0 :(得分:1)

首先让我表达我对生成主键所采取的方法的厌恶,现在就REPEATABLE READ隔离而言,它只能防止更新,你仍然可以读取,这是你的实现的问题,无法防止插入

理想情况下,我建议您重新构建主键生成但如果不可能,则唯一剩下的就是使用SERIALIZABLE隔离,这也可以保护插入,但是根据您确定下一个键值的方式和时间,可能无法以任何方式解决它

答案 1 :(得分:1)

RepeatableRead不会解决这个问题,因为它允许幻像插入,这正是你在这里所拥有的。第二个插入是错误的,因为它没有“看到”前一个插入,并且您有所描述的行为。

您可以使用可序列化隔离或通过执行单独的事务来修复它(前者会增加争用,后者会减少争用,但后者可能无法实现)。

实际上,修复方法是用属性标识约束替换触发器(此可以在现有表上完成,但是存在困难,特别是如果正在使用复制),或者没有使用更好的算法设置新值。