【问题标题】:Spring transaction management for read lock读锁的Spring事务管理
【发布时间】:2017-10-23 19:15:58
【问题描述】:

我正在使用 Spring 进行事务管理。我正在使用 @Transactional 在我的应用程序中实现 spring 事务。我的场景之一是,我的应用程序的两个实例读取特定表的所有记录。在读取和处理记录后,这些记录将被删除。但我的问题是,在一个实例完成读取之前,处理和删除其他实例再次读取这些记录。为了解决这个问题,我计划在事务中使用读锁,以便在第一个事务完成之前所有记录都被锁定。如何使用 Spring 声明性注释来实现这一点。任何帮助表示赞赏。我使用 DB2 作为我的数据库。 谢谢。

【问题讨论】:

  • 如果要删除行,读锁是不够的。你用什么来访问数据库?存储库? Jdbc模板?
  • 我将在读取和处理后删除单个事务中的行。但第二种情况是在那段时间阅读那些记录,这是我不想要的。可序列化隔离对我有帮助吗?
  • 不是真的,你需要做SELECT FOR UPDATE SKIP LOCKED DATA 以获得良好的吞吐量并且两者都做一些实际的工作。
  • DEFAULT (spring-tx-isolation) 默认为“底层数据源”的隔离,配置这个或尝试(至少)READ_COMMITTED ...在你去SERIALIZABLE.. .
  • 不要使用可序列化,它对你没有任何好处。事务将不断回滚,您将浪费时间重做它们而不是处理行。

标签: java database spring transactions spring-transactions


【解决方案1】:

基本上,您希望锁定读取的行以进行更新,并在选择时跳过锁定的行。在原始 SQL 中,这将是

SELECT * FROM FOO FOR UPDATE SKIP LOCKED DATA FETCH FIRST 100 ROWS ONLY;

这样您就不会弄乱其他事务正在使用的行,并且两者都可以愉快地一次处理 100 行。隔离级别应该是READ COMMITTED(大概是你使用的默认值)。

【讨论】:

  • 嗨 Kayaman,感谢您给我一个直接的答复。但不幸的是,我无法更新需要大量批准的 SQL 语句。无论如何我可以在不更改 SQL 语句的情况下做到这一点。
  • 如果您无法胜任工作,请辞职并在您所在的位置找到一份工作。您可以更改事务属性,但不能触摸 SQL?这有什么意义?
  • 您不妨只使用应用程序的单个 实例,而不是把工作做得不好。如果您不允许触摸 SQL,我无法相信他们允许您更改事务属性。
  • 我刚刚尝试在我的选择查询中使用“FOR UPDATE SKIP LOCKED DATA FETCH FIRST 100 ROWS”,似乎两个应用程序都能够读取相同的行。此选择查询未锁定所选行以防止其他实例读取。
  • 那么有问题。 SELECT...FOR UPDATE 在事务期间悲观地锁定行(如果不存在事务则抛出异常)。如果您有权访问可以运行查询的 DB2 实例,您可以自己测试它。你的隔离级别是多少?您确定您正在运行正确的查询吗?你的数据库服务器被恶魔附身了吗?
【解决方案2】:

您可以使用某种分发机制,通过该机制每个实例仅读取/处理与其他实例不同的特定记录。

例如,
1. 在键列上应用 mod %2 函数
从数据库中读取一组记录后:
Instance-1 应该处理 key%2=0 的记录并丢弃/不处理其他记录 Instance-2 应该处理 key%2=1 的记录并丢弃/不处理其他记录
这样,即使两个实例都可以读取相同的记录,我们也可以肯定它们只会被一个节点处理。

【讨论】:

  • 他们为什么还要阅读其他记录?数据库完全能够仅选择 id MOD 2 为 0 或 1 的行。
  • 我建议这样做是因为 Jewel 提到他/她无法更改 SQL 并且需要仅通过代码完成某些事情。否则是的,我们绝对可以为此更新 SQL。
  • 嗨,这看起来不错,但适用于两个实例。如果尝试读取的实例超过两个,我认为这种方法行不通。
猜你喜欢
  • 2015-07-16
  • 1970-01-01
  • 2016-12-02
  • 2013-06-30
  • 2017-05-29
  • 2012-10-16
  • 2015-02-08
相关资源
最近更新 更多