Java 在服务器抛出OptimisticLockException后,事务未完全回滚
假设我有一个带有版本字段(javax.persistence.version annotation)的实体bean AccountBean。在事务处理期间,我的应用程序修改此实体并对其他实体执行数据库操作(插入和更新行)。其中一些实体bean具有@Version字段,但不是全部 当同一AccountBean实体被2个线程并发修改时,抛出OptimistickLockException,并(至少根据服务器日志)回滚事务。然而,实际上只有对冲突的AccountBean实体所做的更改才会回滚,其他所有更改都会提交到数据库中 **编辑:** 我添加了简单的源代码来解决这个问题;应用程序是一个RESTWeb服务;两个测试线程使用相同的帐户id并发调用操作“update”。再次抛出OLE,但假定回滚的事务提交给数据库新的AccountHistory实体:/ 由于事务由容器管理,因此在调用方法更新时启动事务,在返回值时提交事务;这也是OLE被抛出的时候Java 在服务器抛出OptimisticLockException后,事务未完全回滚,java,hibernate,jakarta-ee,jpa,optimistic-locking,Java,Hibernate,Jakarta Ee,Jpa,Optimistic Locking,假设我有一个带有版本字段(javax.persistence.version annotation)的实体bean AccountBean。在事务处理期间,我的应用程序修改此实体并对其他实体执行数据库操作(插入和更新行)。其中一些实体bean具有@Version字段,但不是全部 当同一AccountBean实体被2个线程并发修改时,抛出OptimistickLockException,并(至少根据服务器日志)回滚事务。然而,实际上只有对冲突的AccountBean实体所做的更改才会回滚,其他所有
//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
}
我将应用程序部署在jboss-eap-6.1/jboss-as-7.1.1上,最终使用JRE 1.7,并使用Hibernate(这些服务器的默认版本)。我的persistence.xml文件非常简单。我没有设置任何额外属性。当事务回滚时,该事务中所做的所有更改也将回滚 对于本地事务,这由JDBC连接处理,对于全局事务,则通过回滚所有登记的JDBC事务来处理 所以,Hibernate不能控制什么被回滚或不回滚。是底层事务管理器完成了这一任务
提交某些更改和回滚某些更改的唯一情况是服务代码使用多个事务(例如嵌套事务、REQUIRES_NEW)或从非事务性事务调用两个连续事务性服务。因此,如果第二个回滚,第一个仍将提交,因为第一个服务不是事务性的,因此任何后续服务调用都将登记在它自己的事务中。是否同时提交这两个事务?代码中何时启动它们?如果您可以添加启动事务的代码,将有助于回答。您好,谢谢您的回复。我添加了简单的测试代码来说明这个问题。在连续两次调用update之后,我在AccountHistory表中得到了两个新行。。。