JPA嵌套事务在运行时异常后全部提交/回滚

时间:2019-01-14 11:28:08

标签: java jpa java-ee entitymanager

一段时间后,读取并测试了不同形式的EntityManager实例和Bean并进行了一些嵌套事务处理,最后我找不到在运行时异常之后数据完全回滚的方法,该方法必须接近阶段我想要的是只有一个实体保留在数据库上的情况。 情况如下: 我有一个类实体Car和一个类实体CarPart,Car的一个实例可以包含CarPart的列表,我进行了测试以保持持久性,并且当没有运行时错误发生时,所有工作都像一个魅力。问题是,当抛出运行时错误时(如DB触发错误控制器),有时对象会部分保留。 我正在将JPA与JavaEE和EclipseLink一起使用。我需要一种方法来控制对象将完全持久化或对每个持久化操作进行回滚。 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

JPA中不支持嵌套事务,也没有“正确”执行嵌套事务的已知方法。数据库数据的任何部分回滚也将要求对象状态的部分回滚,这通常是在将您的EntityManager和关联的对象扔掉之后的唯一明智的选择。

如果您正在使用JavaEE,并且将整个“用零件制造汽车”包装在单个事务中,则此行为应立即可用。如果您正在使用单独的事务(如我之前所述:无法嵌套它们),则可能会持久保留汽车,而零件则不会持久。

显而易见的解决方案是仅对这两者使用单个容器管理的事务。

答案 1 :(得分:0)

最后,经过一段时间的测试,我得出了一个适用于我的方案的解决方案。 我不会发布所有代码,而只会发布与问题解决方案相对应的主要部分:

经理班

from ftplib import FTP
from time import sleep

def monitor(server, directory, interval):

  ftp = FTP(server)
  ftp.login('display' '')
  ftp.cwd(directory)

  old_files = []
    try:
        while True:
            new_files = ftp.nlst()
            #print(new_files)
            if len(old_files) != 0 and new_files != old_files:
              changes = [i for i in new_files if i not in old_files]
              print(changes)
        old_files = new_files
        sleep(interval)

    except KeyboardInterrupt:
    ftp.quit()


monitor('10.34.34.34', directory='/var/gunlink/segdfiles/M18A1045BS5038', interval =10 )

存储库类:

@ManagedBean
@ApplicationScoped
@TransactionManagement(TransactionManagementType.BEAN)
public class CarsManager implements Serializable {
    @Resource
    private UserTransaction userTransaction;
    private CarsRepositorySameEM carsRepoSameEM;
    private CarsPartsRepositorySameEM carsPartsRepoSameEM;
    private EntityManager entityManager;
    private Cars car;
    private List<CarsParts> carPartList;

    @Inject
    public CarsManager(@MainEM EntityManager em) {
        this.entityManager = em;
        this.carsRepoSameEM = new CarsRepositorySameEM(this.entityManager);
        this.carsPartsRepoSameEM = new CarsPartsRepositorySameEM(this.entityManager);
    }

    public Cars getCar() {
        return car;
    }

    public void setCar(Cars car) {
        this.car = car;
    }

    public List<CarsParts> getCarPartList() {
        return carPartList;
    }

    public void setCarPartList(List<CarsParts> carPartList) {
       this.carPartList = carPartList;
    }

    public Boolean save() {
        Boolean result = Boolean.TRUE;
        try {
            this.userTransaction.begin();
            this.car = carsRepoSameEM.saveCar(this.car);
            if(carsPartsRepoSameEM.getEntityException().getCode() != 0) {
               this.userTransaction.setRollbackOnly();
            }
            for (int i = 0; i < carPartList.size(); i++) {
                carPartList.get(i).setCarsId(car.getID());
            }
            this.carPartList = carsPartsRepoSameEM.saveParts(carPartList);
            if(carsPartsRepoSameEM.getEntityException().getCode() != 0) {
                this.userTransaction.setRollbackOnly();
            }
            car.setCarsPartsList(this.carPartList);
            this.userTransaction.commit();
        } catch (Exception e) {
            //e.printStackTrace();
            result = Boolean.FALSE;
            try {
                this.userTransaction.rollback();
            } catch (Exception ex) {
            }
        }
        return result;
    }
}

-

@Stateless
public class CarsRepositorySameEM extends AbstractRepository<Cars, Long> {
    ...
    public Cars saveCar(Cars car) throws SystemException {
        try {
            this.entityManager.joinTransaction();
            car = this.create(car);
            this.entityManager.flush();
        } catch (Exception e) {
            this.setEntityException(GenericExceptionType.EX_JPA, -1, "CarsRepositorySameEM", "saveCar()", "Error al persistir el Car", null, e.getMessage());
            //throw e;
        }
        return car;
    }
}

观察:EntityManager是从Producer方法注入的,该方法根据配置动态创建EntityManagerFactory。

同样,正如EclipseLink文档所指的那样,用于配置ServerPlatform(将用于实现与主机容器的集成),我还必须将persistence.xml属性放入

@Stateless
public class CarsPartsRepositorySameEM extends AbstractRepository<CarsParts, Long> {
    ...
    public List<CarsParts> saveParts(List<CarsParts> carsPartsList) throws SystemException {
        try {
            this.entityManager.joinTransaction();
            for (int i = 0; i < carsPartsList.size(); i++) {
                carsPartsList.set(i, this.create(carsPartsList.get(i)));
            }
            this.entityManager.flush();
        } catch (Exception e) {
            this.setEntityException(GenericExceptionType.EX_JPA, -1, "CarsPartsRepositorySameEM", "saveParts()", "Error al persistir las CarsParts", null, e.getMessage());
            //throw e;
        }
        return carsPartsList;
    }
}

使用此属性,确保动态创建的EntityManager将使用事务类型JTA。

感谢答案,并希望本示例可以帮助遇到类似问题的任何人。