我目前有以下事务,其中我要在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
)
我在这些交易中遗漏了什么吗?
谢谢!。
当然,您会得到另一个300的数字。因为插入表1不会生成表2的任何锁,所以表1的Count也不会生成表2的锁] >>。您正在使用10个线程的并发性,因此在线程之间或类似的线程之间没有竞争。您只需要同步线程操作即可获得所需的内容。