首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >数据库读锁

数据库读锁
EN

Stack Overflow用户
提问于 2017-01-30 20:24:03
回答 3查看 1.9K关注 0票数 3

我有一个用例,在这个用例中,我需要在一个事务中执行以下操作:

  1. 启动事务
  2. 将项插入表中
  3. 选择表中的所有项
  4. 将所选项目转储到文件中(此文件是版本化的,另一个程序总是使用最新版本)
  5. 如果上述所有事情都成功了,那么提交事务,如果不是,回滚。

如果两个事务几乎同时开始,则可能在第一个事务A提交已插入表的内容之前(步骤4),第二个事务B已经执行了SELECT操作(步骤2),其结果尚未包含第一个事务插入的项(因为A尚未提交,因此BE 221不可见)。在这种情况下,当A完成时,它将正确地转储包含其插入项的文件File1。稍后,B完成后,它将转储另一个文件File2,该文件只包含插入的项,而不包含A插入的项。由于File2是最近的,所以我们将使用File2。问题是,File2 不包含A插入的项,即使该项在DB中很好。

我想知道,当一个事务在提交或回滚之前,通过锁定表的读(选择)来解决这个问题是否可行,如果是,如何在Spring中使用Oracle作为DB来实现这种锁定。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-01-31 12:13:59

您需要在事务之间进行某种同步:

  1. 启动事务
  2. 获得一个锁,以防止另一个会话中的事务继续进行或等待另一个会话中的事务完成
  3. 将项插入表中
  4. 选择.
  5. .
  6. 提交和释放锁

最简单的方法是使用锁表命令,至少在共享模式下是这样(也可以使用共享行独占或排他模式,但对这种情况来说,它们太有限了)。

这种方法的优点是锁在提交或回滚时自动释放。

缺点是,此锁可能干扰系统中同时更新此表的其他事务,并可能降低总体性能。

另一种方法是使用锁住包。

此锁不影响其他未明确使用该锁的事务。

缺点是这个包很难使用,在提交或回滚时没有释放锁,您必须在事务结束时显式地释放锁,因此所有异常都必须小心处理,否则很容易出现死锁。

另一个解决方案是创建一个包含单个行的“虚拟”表,例如:

代码语言:javascript
复制
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中。

票数 1
EN

Stack Overflow用户

发布于 2017-01-30 20:44:07

使用spring的REPEATABLE_READSERIALIZABLE隔离级别:

REPEATABLE_READ表示脏读和不可重复读取被阻止的常量;幻影读取可能发生.此级别禁止事务读取包含未提交更改的行,还禁止以下情况:一个事务读取一行,第二个事务更改行,第一个事务重新读取行,第二次获得不同的值(“不可重复读取”)。 表示脏读、不可重复读取和幻影读取被阻止的常量.该级别包括ISOLATION_REPEATABLE_READ中的禁止项,并进一步禁止这样的情况:一个事务读取满足where条件的所有行;第二个事务插入满足WHERE条件的行;第一个事务为相同条件重新读取,检索第二次读取中的附加“幻影”行。

使用serializablerepeatable read,将保护组不受不可重复读取的影响:

代码语言:javascript
复制
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,报告查询停止任何更新活动。

票数 0
EN

Stack Overflow用户

发布于 2017-01-31 01:31:31

我认为您需要序列化整个事务。而选择..。因为UPDATE可以工作,它并不真正为您购买任何东西,因为您将选择所有行。您最好使用DBMS_LOCK()获取并释放一个锁。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41944767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档