如何锁定数据库表或一系列编写行?
-
08-10-2019 - |
题
我有一个带有主键的简单表。大多数读取操作以键的确切值获取一行。
每行的数据在按键顺序之前和之后都与行保持一定的关系。因此,当我插入新行时,我需要读取将要输入的2行,进行一些计算然后插入。
显然,关注的是,同时另一个连接可能会在相同的间隔中添加带有键值的行。如果密钥的值与第二个插件完全相同,我将被覆盖,但是如果密钥值不同,但在相同的间隔中,关系可能会被打破。
该解决方案似乎是在我决定添加新行或(如果可能的话)锁定以锁定关键值的间隔时(如果可能的话)锁定整个表格。但是,我希望当时不会阻止仅阅读交易。
我正在使用ODBC C ++的LibodBC ++包装器 在客户端程序和IBM DB2免费版中(尽管DB选择仍然可能会发生变化)。这就是我想做的:
- 以自动命令和默认隔离模式启动连接
- 在需要添加新行时,将自动命令设置为false和隔离模式为序列化
- 读取新钥匙值之前和之后的行
- 计算并插入新行
- 犯罪
- 返回到自动命令和默认隔离模式
这会做这份工作吗?其他交易是否可以同时阅读?还有其他/更好的方法吗?
顺便说一句,我看不到libodbc ++ i/fa的方式来指定仅阅读交易。在ODBC中可能吗?
编辑:感谢您的非常有用的答案,我很难选择一个。
解决方案
如果您的数据库处于可序列化模式,则根本不会遇到任何问题。给定一个键K,要获取上一个键和下一个键,您必须运行以下查询:
select key from keys where key > K order by key limit 1; # M?
select key from keys where key < K order by key desc limit 1; # I?
以上作品在MySQL中起作用。此等效查询在DB2中起作用(来自评论):
select key from keys where key = (select min(key) from keys where key > K);
select key from keys where key = (select max(key) from keys where key < K);
第一个查询设置了一个范围锁定,该范围锁定可防止其他交易插入大于K的密钥,并且小于或等于M。
第二个查询设置了一个范围锁定,该范围锁定了其他交易插入小于K的密钥,并且大于或等于I。
主键上的唯一索引可防止K插入两次。因此,您完全被掩盖了。
这就是交易的目的;因此,您可以像整个数据库锁定一样编写代码。
注意:这需要一个支持真正序列化性的数据库。幸运的是,DB2确实如此。支持真正的序列化性的其他DBM:SQLServer和MySQL/InnoDB。 DBMS不是:Oracle,PostgreSQL!
其他提示
如果您的数据库和存储引擎允许,您应该发行 SELECT FOR UPDATE
对于这两个行,您都在尝试插入之间。
这将与任何并发 SELECT FOR UPDATE
.
缺点是一排锁 10
和 12
(插入 11
)还将阻止选择 8
和 10
(插入 9
).
InnoDB
在 MySQL
也可以放置 next-key
锁定索引,即索引记录的锁定和下一个记录之间的差距。
在这种情况下,您只需要发布 SELECT FOR UPDATE
在第一行,因此在此之前同时插入一行。
但是,这需要迫使索引并提供 range
根据您的查询,索引的条件可能不可能,也可能不可能。
您的一般方法是正确的。但是,您应该使用覆盖两个行和所有可能的行的选择语句。例如:
SELECT * FROM MYTABLE WHERE PKCOL BETWEEN 6 AND 10
在具有悲观锁定和交易隔离级别可序列化的数据库系统中,该选择语句应防止插入新的行,以改变选择的结果。