简体   繁体   English

休眠事务计数器行为

[英]Hibernate Transaction Counter Behaviour

I have the following JPA entity: 我有以下JPA实体:

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

    @Id
    private String metricId;

    @Column
    private long count;

    public Metrics() {
        count = 0;
    }

And I try to update it atomically like this: 我尝试像这样原子地更新它:

//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

However for some reason, this doesn't seem to make updates atomic and I end up with lost updates in concurrent environments. 但是由于某种原因,这似乎无法使更新原子化,并且我最终在并发环境中丢失了更新。 I can solve this by implementing optimistic locking with Hibernate using @Version , but I'm a little surprised that is required. 我可以通过使用@Version使用Hibernate实现乐观锁定来解决此@Version ,但我对此感到有些惊讶。

Why does the above code suffer from lost updates, even with a transaction? 为什么上面的代码即使进行交易也会遭受丢失更新的困扰?

Your are right, only optimistic or pessimistic locking can helps you, if you want to hold valid values exactly in database. 您是正确的,如果您想将有效值准确地保存在数据库中,则只有乐观或悲观锁定可以为您提供帮助。 In your case pessimistic locking would be better, because application works in competitive environment, but optimistic locking would be throw exception again and again. 在您的情况下,悲观锁定会更好,因为应用程序可以在竞争环境中工作,但是乐观锁定会一次又一次地引发异常。 All advantages of Atomic was lost after application server restart or hangups. 在应用程序服务器重新启动或挂断后,Atomic的所有优势都丢失了。

Atomic means only one operation at a time. 原子一次只能进行一次操作。 The java language specification guarantees that reading or writing a variable is atomic unless the variable is of type long or double . Java语言规范保证读取或写入变量是原子的, 除非该变量的类型为longdouble Because the variable (long/double) is written using two separate operations: one that writes the first 32 bits, and a second one which writes the last 32 bits. 因为变量(long / double)是使用两个单独的操作写入的:一个操作写入前32位,第二个操作写入后32位。 That means that another thread might read the value of count , and see the intermediate state. 这意味着另一个线程可能会读取count的值,并看到中间状态。

A simple way to make this operation atomic is to make the variable volatile: 使该操作原子化的一种简单方法是使变量为volatile:

private volatile long count;

Now, the count is never cached by any Thread and it is assured that this variable will always be read by main memory and there will never be a loss of your count in concurrent environment. 现在, count永远不会被任何Thread缓存,并且可以确保该变量将始终被主内存读取,并且在并发环境中永远不会丢失计数。

AtomicLong might interest you too given that you aint using it in an entity class. 鉴于您没有在实体类中使用它, AtomicLong可能也会引起您的兴趣。

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

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