交易中的比赛条件

问题描述 投票:0回答:1

我目前有以下事务,其中我要在TABLE1中插入新注册表,然后使用给定条件的TABLE1计数更新TABLE2

dslContext.transaction(configuration -> {
  DSLContext transactionContext = DSL.using(configuration);

  transactionContext
      .insertInto(TABLE1)
      .columns(TABLE1.fields())
      .values(...).onDuplicateKeyIgnore()
      .execute();

  transactionContext
      .update(TABLE2)
      .set(TABLE2.TABLE1_COUNT, transactionContext.selectCount()
          .from(TABLE1)
          .where(...some criteria...)
      .where(...some criteria...)
      .execute();

});

[当我同时运行此程序,并用10个线程池运行300次时,我希望TABLE2中的最终计数字段为300(我插入新行的300次)。

问题是,当我覆盖count字段时,我遇到了某种竞争条件问题。当我检查计数字段时,我得到的不是300,而是其他数字,但是如果我手动检查TABLE1,则所有注册表都没有问题。如果在并发插入完成后再插入一个注册表,则计数字段将正确更新。

我注意到的是update生成的查询看起来不错,我不应该遇到这个问题:

update table2
set "count" = (select count(*) from table1 where "table2"."something"."id" = ?) 
where "something"."id" = ?

只是添加,而我尝试过的方法是将隔离级别更改为TRANSACTION_SERIALIZABLE,并在代码上实现了一个包装器,该包装器可以在失败时重试(并且确实说could not serialize access due to concurrent update)。这种方法很好用,但似乎不允许使用simple CRUD .store()并发插入(再次说could not serialize access due to concurrent update

我在这些交易中遗漏了什么吗?

谢谢!。

java spring-boot jdbc jooq
1个回答
0
投票

当然,您会得到另一个300的数字。因为插入表1不会生成表2的任何锁,所以表1的Count也不会生成表2的锁] >>。您正在使用10个线程的并发性,因此在线程之间或类似的线程之间没有竞争。您只需要同步线程操作即可获得所需的内容。

© www.soinside.com 2019 - 2024. All rights reserved.