如何防止选择和更新之间的竞争条件

时间:2016-12-15 07:03:19

标签: multithreading postgresql jdbc locking

我正在研究分类帐模块。在那个过程中,我必须按顺序执行这些任务

  1. 从源(table1 row1)选择余额
  2. 从目的地选择余额(table1 row2)
  3. 使用某种逻辑修改余额
  4. 更新资源余额(table1 row1)
  5. 更新目的地余额(table1 row2)
  6. 提交更改
  7. 将交易插入交易表。
  8. 在多线程环境中,线程在上一次线程更新和提交之前获得平衡。 在Postgres中,对线程进行锁定,直到线程提交为止。在这种情况下,我看到了一个傻瓜。

    尝试使用synchronized块作为整个模式。没有帮助。 不能使用SELECT FROM UPDATE,因为更改余额的逻辑取决于其他操作。

    以下是一些日志,在[1]线程进入更新部分之前,其他线程收集现有余额。

    [DEBUG] [2016-12-15 10:49:53,893] [1] - Src Ledger_book_idLB001
    [DEBUG] [2016-12-15 10:49:53,893] [1] - Src Balance2500.0
    [DEBUG] [2016-12-15 10:49:53,897] [1] - Dest Ledger_book_idLB002
    [DEBUG] [2016-12-15 10:49:53,897] [1] - Dest Balance0.0
    [DEBUG] [2016-12-15 10:49:53,898] [15] - Src Ledger_book_idLB001
    [DEBUG] [2016-12-15 10:49:53,898] [15] - Src Balance2500.0
    [DEBUG] [2016-12-15 10:49:53,899] [16] - Src Ledger_book_idLB001
    [DEBUG] [2016-12-15 10:49:53,899] [16] - Src Balance2500.0
    [DEBUG] [2016-12-15 10:49:53,900] [16] - Dest Ledger_book_idLB002
    [DEBUG] [2016-12-15 10:49:53,900] [15] - Dest Ledger_book_idLB002
    

    任何帮助表示赞赏:)请评论是否有任何关于这种情况的具体疑问。

1 个答案:

答案 0 :(得分:0)

From the docs

  

当锁定子句出现在子SELECT中时,锁定的行是子查询返回到外部查询的行。这可能涉及的行数少于单独检查子查询所表明的行数,因为来自外部查询的条件可能用于优化子查询的执行。

所以你可以这样做......

您还应该阅读有关CTE的页面,尤其是DATA-MODIFYING

WITH s1 AS (
  SELECT balance FROM source
  FOR UPDATE
), s2 AS (
  SELECT balance destination
  FOR UPDATE
), u1 AS (
  UPDATE source SET balance = ...
  WHERE... -- potential join to S2 if you need destination
  RETURNING -- whatever you need (if anything)
), u2 AS (
  UPDATE source SET balance = ...
  WHERE... -- potential join to S1 if you need source
  RETURNING -- whatever you need (if anything)
)
INSERT INTO transactions (foo,date) VALUES (bar,now());