gpt4 book ai didi

java - 竞争条件虽然使用事务

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:14:29 24 4
gpt4 key购买 nike

我有这笔交易:

em.getTransaction().begin();
{
final Payment payment = em.find(Payment.class, id);
if (payment.status != Status.INIT)
throw new IllegalStateException("Cannot set to PAID, is not INIT but " + status);

payment.status = Status.PAID;

}
em.getTransaction().commit();
log.info("Payment " + id + " was paid");

但是,正如您在此处所见,事务并没有阻止竞争条件:

[11:10:18.265] INFO  [PaymentServlet] [MSP] Status COMPLETED 
[11:10:18.265] INFO [PaymentServlet] Payment c76f9e75-99d7-4721-a8ac-e3a638dd8317 was paid
[11:10:18.267] INFO [PaymentServlet] [MSP] Status COMPLETED
[11:10:18.267] INFO [PaymentServlet] Payment c76f9e75-99d7-4721-a8ac-e3a638dd8317 was paid

付款设置为PAID两次。没有抛出我的异常,也没有回滚或任何东西。

我做错了什么?

最佳答案

你需要使用乐观锁。乐观锁定是冲突更新很少见的地方,因此在偶尔发生的事务发生时回滚是可以接受的。悲观锁定导致数据库在使用对象时持有对象的锁,有效地单线程处理所有内容并可能导致性能问题。参见 http://en.wikibooks.org/wiki/Java_Persistence/Locking#JPA_2.0_Locking以获得更详细的解释。

要解决这里的问题,应该在Payment中添加一个字段(传统的声明是private Long version),并给它加上JPA @Version注解。如果您手动管理架构,请确保相应的列存在于正确的表中。然后,JPA 将使用此字段检查冲突更新并在存在冲突时回滚事务。

更新:更多关于悲观锁定的信息:https://blogs.oracle.com/carolmcdonald/entry/jpa_2_0_concurrency_and简而言之,您可以配置 JPA 来锁定对象,但很少有人认为这样做是个好主意。换句话说,如果您对 JDBC 进行手动编码查询,则必须在每个选择的末尾写入“for update”以导致悲观锁定;默认情况下不锁定读取,因为它会让数据库和数据库用户哭泣。

关于java - 竞争条件虽然使用事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10597713/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com