繁体   English   中英

休眠事务计数器行为

[英]Hibernate Transaction Counter Behaviour

我有以下JPA实体:

@Entity(name="metrics")
public class Metrics {

    @Id
    private String metricId;

    @Column
    private long count;

    public Metrics() {
        count = 0;
    }

我尝试像这样原子地更新它:

//Begin transaction
Metrics result = em.find(Metrics.class, id);

if (result == null) {
    result = new Metrics();
    result.metricId = id;
    result.count++;
    em.persist(result);
} else {
    result.count++;
    em.merge(result);
}
//Commit transaction

但是由于某种原因,这似乎无法使更新原子化,并且我最终在并发环境中丢失了更新。 我可以通过使用@Version使用Hibernate实现乐观锁定来解决此@Version ,但我对此感到有些惊讶。

为什么上面的代码即使进行交易也会遭受丢失更新的困扰?

您是正确的,如果您想将有效值准确地保存在数据库中,则只有乐观或悲观锁定可以为您提供帮助。 在您的情况下,悲观锁定会更好,因为应用程序可以在竞争环境中工作,但是乐观锁定会一次又一次地引发异常。 在应用程序服务器重新启动或挂断后,Atomic的所有优势都丢失了。

原子一次只能进行一次操作。 Java语言规范保证读取或写入变量是原子的, 除非该变量的类型为longdouble 因为变量(long / double)是使用两个单独的操作写入的:一个操作写入前32位,第二个操作写入后32位。 这意味着另一个线程可能会读取count的值,并看到中间状态。

使该操作原子化的一种简单方法是使变量为volatile:

private volatile long count;

现在, count永远不会被任何Thread缓存,并且可以确保该变量将始终被主内存读取,并且在并发环境中永远不会丢失计数。

鉴于您没有在实体类中使用它, AtomicLong可能也会引起您的兴趣。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM