假设我有一个带有版本字段的实体bean AccountBean(javax.persistence.Version annotation)。在事务期间,我的应用程序修改此实体并对其他实体执行数据库操作(插入和更新行)。其中一些实体bean有@Version字段但不是全部。
当同一个AccountBean实体被2个线程同时修改时,抛出OptimistickLockException并且(至少根据服务器日志)回滚事务。但是,只有对冲突的AccountBean实体所做的更改才会实际回滚 - 其他所有内容都将提交给数据库。
**编辑:** 我添加了简单的源代码来解决这个问题;该应用程序是一个REST Web服务;两个测试线程使用相同的帐户ID同时调用“update”操作。再一次抛出OLE,然而所谓的回滚事务提交给数据库新的AccountHistory实体:/ 由于事务由容器管理,因此在调用方法更新时启动事务,在重新调整值时提交事务;这也是抛出OLE的时候。
//UpdateAccount.java
@Stateless
@Path("account")
public class UpdateAccount {
@PersistenceContext
EntityManager em;
@Path("update")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String update(Long accountId) {
Account account = em.find(Account.class, accountId);
if(null == account) {
return "account not found";
} else {
return executeUpdate(account);
}
}
String executeUpdate(Account account) {
Integer newValue = account.getValue() + 1;
em.persist(getAccountHistory(account, newValue));
account.setValue(newValue);
return "ok";
}
AccountHistory getAccountHistory(Account account, Integer newValue) {
AccountHistory history = new AccountHistory();
history.setId(new Date().getTime());
history.setAccount(account);
history.setValueBefore(account.getValue());
history.setValueAfter(newValue);
return history;
}
}
//Account.java
@Entity
public class Account {
@Id
private Long id;
@Column
private Integer value;
@Version
private Long version;
(...)//getters, setters etc
}
//AccountHistory.java
@Entity
public class AccountHistory {
@Id
private Long id;
@Column
private Integer valueBefore;
@Column
private Integer valueAfter;
@ManyToOne
@JoinColumn(name = "idaccount")
private Account account;
(...)//getters, setters etc
}
我使用JRE 1.7在jboss-eap-6.1 / jboss-as-7.1.1Final上部署我的应用程序,并使用Hibernate(这些服务器的版本默认值)。我的persistence.xml文件非常简单。我没有设置任何额外的属性。
答案 0 :(得分:0)
当事务回滚时,该事务中所做的所有更改也将被回滚。
对于本地事务,这由JDBC连接处理,对于全局事务,通过回滚所有登记的JDBC事务来处理。
因此,Hibernate无法控制得到滚动支持的内容。这是诀窍的基础事务管理器。
提交某些更改并且某些更改是滚动支持的唯一情况是,当您的服务代码使用多个事务(例如嵌套事务,REQUIRES_NEW)时,或者从非事务性事务中调用两个连续事务服务时。因此,如果第二次回滚,则第一次回滚是承诺的,因为第一次服务不是交易的,因此任何连续的服务呼叫都被列入其自己的交易中。