我有一个用例,在这个用例中,我需要在一个事务中执行以下操作:
如果两个事务几乎同时开始,则可能在第一个事务A提交已插入表的内容之前(步骤4),第二个事务B已经执行了SELECT操作(步骤2),其结果尚未包含第一个事务插入的项(因为A尚未提交,因此BE 221不可见)。在这种情况下,当A完成时,它将正确地转储包含其插入项的文件File1。稍后,B完成后,它将转储另一个文件File2,该文件只包含插入的项,而不包含A插入的项。由于File2是最近的,所以我们将使用File2。问题是,File2 不包含A插入的项,即使该项在DB中很好。
我想知道,当一个事务在提交或回滚之前,通过锁定表的读(选择)来解决这个问题是否可行,如果是,如何在Spring中使用Oracle作为DB来实现这种锁定。
发布于 2017-01-31 12:13:59
您需要在事务之间进行某种同步:
最简单的方法是使用锁表命令,至少在共享模式下是这样(也可以使用共享行独占或排他模式,但对这种情况来说,它们太有限了)。
这种方法的优点是锁在提交或回滚时自动释放。
缺点是,此锁可能干扰系统中同时更新此表的其他事务,并可能降低总体性能。
另一种方法是使用锁住包。
此锁不影响其他未明确使用该锁的事务。
缺点是这个包很难使用,在提交或回滚时没有释放锁,您必须在事务结束时显式地释放锁,因此所有异常都必须小心处理,否则很容易出现死锁。
另一个解决方案是创建一个包含单个行的“虚拟”表,例如:
CREATE TABLE my_special_lock_table(
int x
);
INSERT INTO my_special_lock_table VALUES(1);
COMMIT:然后使用SELECT x FROM my_special_lock_table FOR UPDATE
或者--甚至更简单--事务中的简单UPDATE my_special_lock_table SET x=x。
这将在此表中的一行上放置一个独占锁,并且只同步这一个事务。
缺点是必须创建另一个“虚拟”表。
但是该解决方案不影响系统中的其他事务,锁在提交或回滚时自动释放,并且是可移植的-它应该在所有其他数据库中工作,而不仅仅是在Oracle中。
发布于 2017-01-30 20:44:07
使用spring的REPEATABLE_READ或SERIALIZABLE隔离级别:
REPEATABLE_READ表示脏读和不可重复读取被阻止的常量;幻影读取可能发生.此级别禁止事务读取包含未提交更改的行,还禁止以下情况:一个事务读取一行,第二个事务更改行,第一个事务重新读取行,第二次获得不同的值(“不可重复读取”)。 表示脏读、不可重复读取和幻影读取被阻止的常量.该级别包括ISOLATION_REPEATABLE_READ中的禁止项,并进一步禁止这样的情况:一个事务读取满足where条件的所有行;第二个事务插入满足WHERE条件的行;第一个事务为相同条件重新读取,检索第二次读取中的附加“幻影”行。
使用serializable或repeatable read,将保护组不受不可重复读取的影响:
connection 1: connection 2:
set transaction isolation level
repeatable read
begin transaction
select name from users where id = 1
update user set name = 'Bill' where id = 1
select name from users where id = 1 |
commit transaction |
|--> executed here在这个场景中,update将被阻塞,直到第一个事务完成。
更高的隔离级别很少被使用,因为它们降低了可以同时在数据库中工作的人数。在最高级别,serializable,报告查询停止任何更新活动。
发布于 2017-01-31 01:31:31
我认为您需要序列化整个事务。而选择..。因为UPDATE可以工作,它并不真正为您购买任何东西,因为您将选择所有行。您最好使用DBMS_LOCK()获取并释放一个锁。
https://stackoverflow.com/questions/41944767
复制相似问题