【问题标题】:Concurrent transaction issue on clustered environment集群环境下的并发事务问题
【发布时间】:2014-10-16 06:52:04
【问题描述】:

我在集群环境中运行的 Web 应用程序中遇到了一种情况。

我们有 2 个节点(都有 JVM)

  1. 节点1
  2. 节点2

我正在我的应用程序中运行一个数据库事务,其中读取了 sequence_no,然后我们将其递增 1,例如

select sequence from some_table;

nextsequence = sequence + 1; // incrementing sequence 

update some_table set sequence = nextsequence;  // set the next sequence

现在发生的请求转到 Node1 并增加序列号。但由于 node1 上的内存不足错误,被缓慢地提交到数据库(需要 1 分钟)。同时另一个请求转到Node2并获取序列号。从数据库中更新它。所以两个请求都有相同的序列,我们不会因为我们想要唯一的序列号。对于所有请求。

我们无法同步事务,因为它没有帮助,因为它运行在不同的 JVM 上。

我想知道下一步该怎么做?非常感谢任何帮助。

【问题讨论】:

  • 您使用的是哪个数据库?任何主要的数据库支持排序(在插入时或通过触发器等) - 你不应该自己实现它!
  • 我们使用的是 Oracle 11g。我知道自己实现序列是不好的方法,但这是我需要修复的现有代码。
  • 使用数据库序列,或者至少在读取序列时使用悲观锁(选择更新)。
  • 你不能实现一个 oracle 序列并替换检索序列的代码来调用它吗?您显然已经拥有数据库连接。毕竟,您的记录主键不需要是连续的。您可以跳过它们的值,只要它们是唯一的,并且您将解决 2 个问题。 1. 糟糕的实现,2. 你的并发问题:)
  • 嗯,奇怪,但注意到了。如果您下定决心要走这条路,您可以使用的一种技术是乐观并发控制。因此,您仅在序列与您期望的序列匹配时才更新序列,或者您可以通过存储序列上次更新时间的时间戳并进行类似检查来实现此目的。如果它们匹配,则提交您的更改,否则抛出异常,返回您的应用程序并获取它以检索新序列并重新尝试。

标签: java concurrency transactions jvm optimistic-locking


【解决方案1】:

如果您无法像许多 cmets 建议的那样在数据库中控制这一点,您的下一个选择是实施某种形式的简单版本控制。

一种方法是将更新语句更改为:

update some_table set sequence = nextsequence where sequence = [sequence you just read];

然后查看更新了多少条记录(例如,PreparedStatement 的 executeUpdate() 将为您提供此值)。如果结果为 0,那么您的流程的另一个实例将您击败,因此您以某种方式处理它(抛出和错误,选择另一个序列号,...)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多