Spring 数据库读锁定
我有一个用例,需要在一个事务中执行以下操作: 启动事务 将项目插入表中 选择表中的所有项目 将所选项目转储到一个文件中此文件有版本控制,另一个程序始终使用最新版本 如果上述所有操作都成功,则提交事务,否则回滚。 如果两个事务几乎同时开始,则有可能在第一个事务A提交其在表步骤4中插入的内容之前,第二个事务B已经执行了SELECT操作步骤2,其结果尚未包含第一个事务A插入的项目,因为它尚未由A提交,因此B不可见。在这种情况下,当A完成时,它将正确转储包含其插入项的文件File1。稍后,B完成后,它将转储另一个文件File2,该文件File2仅包含其插入的项,而不包含由A插入的项。由于File2是较新的,因此我们将使用File2。问题是,文件2不包含由插入的项,即使该项在数据库中也很好 我想知道,当事务在表中插入某些内容直到提交或回滚时,通过锁定表的readSELECT来解决此问题是否可行,如果可行,如何在Spring中使用Oracle作为DB来实现此锁定。使用Spring的可重复读取或可序列化隔离级别: REPEATABLE_READ一个常数,指示脏读和 防止不可重复读取;可能发生幻象读取。这 级别禁止事务读取未提交的行 它的变化,而且它还禁止一个 事务读取一行,第二个事务更改该行,然后 第一个事务重新读取该行,第二个事务获取不同的值 对不可重复的读取进行计时 SERIALIZABLE一个常量,指示脏读,不可重复 防止读取和幻象读取。这一级别包括 隔离禁止\u可重复\u读取并进一步禁止 一个事务读取满足where的所有行的情况 条件下,第二个事务插入满足该条件的行 其中条件,并且第一个事务将重新读取相同的条件 条件,检索第二次读取中的附加幻影行 使用可串行化或可重复读取,将保护组不受不可重复读取的影响:Spring 数据库读锁定,spring,oracle,concurrency,transactions,locking,Spring,Oracle,Concurrency,Transactions,Locking,我有一个用例,需要在一个事务中执行以下操作: 启动事务 将项目插入表中 选择表中的所有项目 将所选项目转储到一个文件中此文件有版本控制,另一个程序始终使用最新版本 如果上述所有操作都成功,则提交事务,否则回滚。 如果两个事务几乎同时开始,则有可能在第一个事务A提交其在表步骤4中插入的内容之前,第二个事务B已经执行了SELECT操作步骤2,其结果尚未包含第一个事务A插入的项目,因为它尚未由A提交,因此B不可见。在这种情况下,当A完成时,它将正确转储包含其插入项的文件File1。稍后,B完成后,它将
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
在这种情况下,更新将被阻止,直到第一个事务完成
很少使用更高的隔离级别,因为它们减少了可以同时在数据库中工作的人数。在可序列化的最高级别,报告查询将停止任何更新活动。我认为您需要序列化整个事务。当一个选择。。。因为更新可以工作,所以它并不能真正为您买任何东西,因为您将选择所有行。您也可以使用DBMS_lock获取并释放锁,您需要在事务之间进行某种同步: 启动事务 获取锁以防止另一个会话中的事务继续或等待另一个会话中的事务完成 将项目插入表中 选择 ...... 提交并释放锁 最简单的方法是使用命令,至少在共享模式下也可以使用共享行排他模式或排他模式,但对于这种情况,这些模式限制太多。 这种方法的优点是在提交或回滚时自动释放锁。 缺点是,此锁可能会干扰系统中同时更新此表的其他事务,并可能降低总体性能 另一种方法是使用包。此锁不会影响其他未明确使用该锁的事务。值得注意的是,这个包很难使用,在提交或回滚时不会释放锁,必须在事务结束时明确释放锁,因此必须小心处理所有异常,否则很容易发生死锁 另一种解决方案是创建一个包含单行的虚拟表,例如:
CREATE TABLE my_special_lock_table(
int x
);
INSERT INTO my_special_lock_table VALUES(1);
COMMIT:
然后使用my_special_lock_表中的SELECT x进行更新
或者-更简单-在事务中简单地更新my_special_lock_表集x=x。
这将在此表中的一行上放置独占锁,并仅同步这一个事务。
缺点是必须创建另一个虚拟表。
但此解决方案不会影响系统中的其他事务,锁在提交或回滚时自动释放,并且是可移植的-它应该可以在所有其他数据库中工作,而不仅仅是在Oracle中。两个事务几乎同时开始,听起来像是多个进程/进程试图同时访问数据库,是这样吗?@Alex,可能是不同的进程从不同的服务器执行此事务
nt物理机器。这些是事务。。长还是短?这取决于你所说的长或短,通常是几秒钟。我会将DB操作封装在一个进程中,所有其他进程都必须通过该进程访问DB。在这个过程中,我将创建一个等待队列,以串行方式处理数据库访问。@Zamani我认为您的示例没有涵盖我的用例。我的用例涉及插入而不是更新,我正在执行一个范围选择所有行而不是选择一行。因此,可重复读取无法避免幻象读取。@Gab是好人, 这些都是我从网上复制的例子。插入而不是更新也是一种修改,Oracle应该理解这一点。选择一个范围是一样的,我认为你的DB会理解这些。这是不一样的,见@Gab是好人, 那篇文章说,可序列化隔离级别导致了一种场景,在这种场景中,上面提到的任何问题都不会发生,我认为这正是您所需要的。