如何在JPA中回滚一系列持久化语句?

时间:2015-12-19 05:15:32

标签: java jpa

我有一种情况需要回滚一系列持久化方法。 我在我的控制器类中有一个方法,我从那里调用persist方法。

控制器类:

@EJB
private jpa.session.ClassMasterFacade ejbFacadeCM;
@EJB
private jpa.session.StudentMasterFacade ejbFacadeSM;
@EJB
private jpa.session.ParentsMasterFacade ejbFacadePM;
@EJB
private jpa.session.AddressMasterFacade ejbFacadeAM;

public String confirmData() {
    try {
        ejbFacadeSM;.create(selectedSM);
        ejbFacadeCM;.create(selectedCM)
        ejbFacadeAM;.create(selectedAM);
        ejbFacadePM;.create(selectedPM);
    } catch (Exception e) {
        //rollback all
        JsfUtil.addErrorMessage(e, ResourceBundle.getBundle ("/resources/Bundle").getString("PersistenceErrorOccured"));
        return null;
    }
 }

示例Facade类:

@Stateless
public class ClassMasterFacade extends AbstractFacade<ClassMaster> {

    @PersistenceContext(unitName = "sdjv_smsPU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public ClassMasterFacade() {
        super(ClassMaster.class);
    }

}

所有其他门面类与上面的类相似。抽象类是:

public abstract class AbstractFacade<T> {
    private Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }
}

如果发现任何异常,我想回滚所有create方法。

我搜索并找到了一些答案:

我是JPA的新手,刚开始探索它。我错过了一些概念吗?

直到有问题,不知道它是否相关。在所有实体类中,我有一个自动生成的密钥更新。问题是如果在第二个create语句中发生异常,则会生成第一个create语句的autogenerated键,但仍然没有在mysql中更新为excepted ..但是如果成功所有语句,则键序列被破坏。

实体类:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "class_group_id")
private Integer classGroupId;

2 个答案:

答案 0 :(得分:4)

使用javax.transaction.UserTransaction,您可以在任何标准Java EE环境中使用它。

使用非常简单,注入并使用以下方法:

  • begin()开始交易
  • commit()如果所有操作都成功并且您想提交结果
  • rollback()如果发生错误并且您希望回滚到调用begin()的时间点

请参阅:Oracle documentation on UserTransaction

@Resource
UserTransaction tran;

...

public void confirmData (){

    tran.begin();
    try {
        ejbFacadeSM.create(selectedSM);
        ejbFacadeCM.create(selectedCM)
        ejbFacadeAM.create(selectedAM);
        ejbFacadePM.create(selectedPM);

        // Create's succeeded, commit transaction.
        tran.commit();
    } catch (Exception e) {
        // Error occurred, rollback transaction
        tran.rollback();
    }
}

答案 1 :(得分:0)

回滚可以由事务自动完成。只需告诉您的方法它必须在事务中运行,并且如果不存在则应创建新事务。您可以通过使用事务属性REQUIRES_NEW

注释方法来执行此操作
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public String confirmData() {
    try{
        ejbFacadeSM.create(selectedSM);
        ejbFacadeCM.create(selectedCM)
        ejbFacadeAM.create(selectedAM);
        ejbFacadePM.create(selectedPM);
    }catch(PersistenceException e){
        //do some stuff
    }
}

如果您的某个语句因PersistenceException而失败,那么当您的事务结束时,所有操作都将回滚。交易以您的方法结束。

请注意一个例外,因为规范(在JSR 338中)说:

  

PersistenceException的所有实例,除了实例   NoResultExceptionNonUniqueResultExceptionLockTimeoutException和   QueryTimeoutException将导致当前事务,如果是的话   active和持久化上下文已连接到它,需要标记   用于回滚。

示例:如果您的第4个陈述 ejbFacadePM.create(selectedPM) 失败,例如a LockTimeoutException,只回滚第4个语句,但您的交易不会被标记为回滚。接下来,您将到达代码的catch块。这使您有机会通过编写一些代码再次尝试第4个语句来从异常中恢复。当您离开confirmData()方法时,事务仍将通过您在先前ejbFacadeXX方法中所做的更改提交给数据库。

如果您仍然说您已经回滚完整的事务,包括发出的所有语句,无论发生什么类型的异常,您仍然可以告诉事务在catch块中回滚。因此,对于 Bean Managend Transactions (BMT)使用rollback()或对容器管理的交易(CMT)使用setRollbackOnly()。如果您未将事务设置为bean管理(例如,使用@TransactionManagement( TransactionManagementType.BEAN )),则您的事务很可能是容器管理的,这是自JEE 5以来的默认事务。

建议不要使用BMT,因为它要求您的应用程序执行您的服务器已经可以为您完成的工作。