您有两种方法来处理这种情况: 悲观主义者 锁定或 乐观主义者 锁定。但是您似乎都不使用两者,这可能解释了错误的行为。
使用乐观锁定,Hibernate将检查在读取和保存用户帐户之间是否没有更改用户帐户。然后,并发事务可能会失败并回滚。
使用悲观锁定,您可以在读取行时锁定该行,并且仅在事务完成时才将其解锁。这样可以防止并发事务读取会过时的数据。
刷新实体可能会读取新数据,也可能不会读取新数据,这取决于当前事务是否已经提交,但这也不是解决方案。由于似乎还创建了用户帐户(如果该帐户不存在),因此您不能如此轻松地应用悲观主义者锁定。我建议您然后使用乐观锁定(例如,使用时间戳来检测并发修改)。
阅读关于SO的另一个有关悲观主义者和乐观主义者锁定的问题。还可以查看hibernate章节“
事务和并发
”和“
hibernate注释 ”。
它应该是一样简单加入
@Version上的相应字段中,
optimisticLockStrategy
默认值是
VERSION(一个单独的列被使用)。
-更新-
您可以测试它是否可以在测试用例中使用。我创建了一个简单的实体
Counter带
ID,
value以及
version多个领域。
public class Counter implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Basic(optional = false) @Column(name = "ID") private Integer id; @Column(name = "VALUE") private Integer value; @Column(name = "VERSION") @Version private Integer version; ...}如果您 顺序 更新一个实体,它将起作用:
id = insertEntity( ... ); em1.getTransaction().begin(); Counter c1 = em1.find( Counter.class, id ); c1.setValue( c1.getValue() + 1 ); em1.flush(); em1.getTransaction().commit(); em2.getTransaction().begin(); Counter c2 = em2.find( Counter.class, id ); c2.setValue( c2.getValue() + 1 ); em2.flush(); // OK em2.getTransaction().commit();
我通过
value=2和获得了一个实体
version=2。
如果我模拟两个 并发 更新:
id = insertEntity( ... );em1.getTransaction().begin();em2.getTransaction().begin();Counter c1 = em1.find( Counter.class, id );Counter c2 = em2.find( Counter.class, id );c1.setValue( c1.getValue() + 1 );em1.flush(); em1.getTransaction().commit();c2.setValue( c2.getValue() + 1 );em2.flush(); // fail em2.getTransaction().commit();
然后第二次冲洗失败:
Hibernate: update COUNTER set VALUE=?, VERSION=? where ID=? and VERSION=?Hibernate: update COUNTER set VALUE=?, VERSION=? where ID=? and VERSION=?Dec 23, 2009 11:08:46 AM org.hibernate.event.def.AbstractFlushingEventListener performExecutionsSEVERE: Could not synchronize database state with sessionorg.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.ewe.Counter#15] at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1765)
之所以如此,是因为SQL语句中的实际参数是:
update COUNTER set VALUE=1, VERSION=1 where ID=xxx and VERSION=0 --> 1 row updated update COUNTER set VALUE=1, VERSION=1 where ID=xxx and VERSION=0 --> 0 row updated, because version has been changed in between



