Java 在服务器抛出OptimisticLockException后,事务未完全回滚

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实体所做的更改才会回滚,其他所有

假设我有一个带有版本字段(javax.persistence.version annotation)的实体bean AccountBean。在事务处理期间,我的应用程序修改此实体并对其他实体执行数据库操作(插入和更新行)。其中一些实体bean具有@Version字段,但不是全部

当同一AccountBean实体被2个线程并发修改时,抛出OptimistickLockException,并(至少根据服务器日志)回滚事务。然而,实际上只有对冲突的AccountBean实体所做的更改才会回滚,其他所有更改都会提交到数据库中

**编辑:** 我添加了简单的源代码来解决这个问题;应用程序是一个RESTWeb服务;两个测试线程使用相同的帐户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
}
  • 我期望所有的变化都会倒退,这是错误的吗
  • 我可以手动强制完成回滚吗?我尝试手动管理交易, 捕获OLE并调用回滚(如中所述)。但是,当我捕获到异常时,事务是 已标记为已回滚

  • 我将应用程序部署在jboss-eap-6.1/jboss-as-7.1.1上,最终使用JRE 1.7,并使用Hibernate(这些服务器的默认版本)。我的persistence.xml文件非常简单。我没有设置任何额外属性。

    当事务回滚时,该事务中所做的所有更改也将回滚

    对于本地事务,这由JDBC连接处理,对于全局事务,则通过回滚所有登记的JDBC事务来处理

    所以,Hibernate不能控制什么被回滚或不回滚。是底层事务管理器完成了这一任务


    提交某些更改和回滚某些更改的唯一情况是服务代码使用多个事务(例如嵌套事务、REQUIRES_NEW)或从非事务性事务调用两个连续事务性服务。因此,如果第二个回滚,第一个仍将提交,因为第一个服务不是事务性的,因此任何后续服务调用都将登记在它自己的事务中。

    是否同时提交这两个事务?代码中何时启动它们?如果您可以添加启动事务的代码,将有助于回答。您好,谢谢您的回复。我添加了简单的测试代码来说明这个问题。在连续两次调用update之后,我在AccountHistory表中得到了两个新行。。。