Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate-在一个实体失败时回滚实体列表_Java_Hibernate - Fatal编程技术网

Java Hibernate-在一个实体失败时回滚实体列表

Java Hibernate-在一个实体失败时回滚实体列表,java,hibernate,Java,Hibernate,我只是在做一个项目,在我的mysql数据库中创建、更改用户。因此,我有UserService(REST),它创建了一个用户和一个GenericDAO类,我可以在其中持久化用户。在我的DAO中,我为每个用户开始、持久化和提交一个事务。创建单个用户或查找用户的工作非常完美 现在,我面临的问题是保存或更新用户列表。特别是如果一个用户无法持久化(例如重复用户),则应回滚hole事务。它在我当前的设置中不起作用 我的第一个想法是用一种单独的方法外包提交。通过对所有用户进行循环,我只保留他们。在循环结束时,

我只是在做一个项目,在我的mysql数据库中创建、更改用户。因此,我有UserService(REST),它创建了一个用户和一个GenericDAO类,我可以在其中持久化用户。在我的DAO中,我为每个用户开始、持久化和提交一个事务。创建单个用户或查找用户的工作非常完美

现在,我面临的问题是保存或更新用户列表。特别是如果一个用户无法持久化(例如重复用户),则应回滚hole事务。它在我当前的设置中不起作用

我的第一个想法是用一种单独的方法外包提交。通过对所有用户进行循环,我只保留他们。在循环结束时,我将调用我的方法来提交所有内容。如果一个或多个用户失败,我可以通过回滚来捕获他们。这是一个好方法吗

抽象DAO(当前)

公共抽象类GenericDAO实现IGenericDAO{
@持久上下文
受保护的EntityManager em=null;
私有标准生成器cb=null;
私人课堂;
公共通用DAO(1类){
this.clazz=class1;
this.em=EntityManagerUtil.getEntityManager();
这个.em.getCriteriaBuilder();
}
公共最终无效集合(类别集合){
this.clazz=clazzToSet;
}
公共T创建(T实体){
试一试{
em.getTransaction().begin();
em.persist(实体);
em.getTransaction().commit();
返回实体;
}捕获(持久异常e){
em.getTransaction().rollback();
返回null;
}
}
公共找不到(内部id){
返回em.find(this.clazz,id);
}
公共列表findAll(){
返回em.createQuery(“from”+this.clazz.getName()).getResultList();
}
/**保存对持久对象所做的更改*/
公共无效更新(T实体){
em.getTransaction().begin();
合并(实体);
em.getTransaction().commit();
}
/**从数据库中的持久存储中删除对象*/
公共作废删除(T实体){
em.getTransaction().begin();
em.remove(实体);
em.getTransaction().commit();
}

最方便的解决方案不是简单地添加像
createAll()/updateAll()
这样的方法吗

添加单独的公共方法来启动和持久化事务,如
start()
commit()
会产生一大堆问题,因为这意味着您会突然在
Dao
及其客户端之间引入有状态的对话

Dao
方法现在需要按特定顺序调用,更糟糕的是,
EntityManager
事务的状态将被保留在使用您的
Dao的一次服务调用结束时,后续调用将错误地假定事务尚未启动,并且该调用将“无明显原因”地失败(更不用说,当事务实际上处于挂起状态时,原始调用将显示为已完成)。这会产生难以调试且难以恢复的错误

编辑正如我在下面的评论中所指出的,在多层应用程序结构中正确地进行编程事务管理是一件棘手的事情,因此,我建议大家看看声明式事务管理

然而,如果您坚持自己管理交易,我可能会介绍一些类似于
交易模板的东西:

public class TransactionTemplate {
   
    private EntityManager em; //populated in a constructor, for instance

    public void executeInTransaction(Runnable action) {
        try {
            em.getTransaction().begin();
            action.run();
            em.getTransaction().commit();
        } catch (Exception e) {
            em.getTransaction().rollback();
        } finally {
            em.clear(); // since you're using extended persistence context, you might want this line
        }
    }

}
并将其用于如下服务:

public class UserService {

    private TransactionTemplate template;
    private RoleDao roleDao;
    private UserDao userDao; //make sure TransactionTemplate and all Daos use the same EntityManager - for a single transaction, at least

    public void saveUsers(Collection<User> users, String roleName) {
        template.executeInTransaction(() -> {
            Role role = roleDao.findByName(roleName);
            users.forEach(user -> {
                user.addRole(role);
                userDao.create(user);
            });
            // some other operations
        });
    }

}
公共类用户服务{
私有交易模板;
列兵列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛列岛;
private UserDao UserDao;//确保TransactionTemplate和所有DAO至少对单个事务使用相同的EntityManager
公共void存储用户(集合用户、字符串角色名){
template.executeInTransaction(()->{
Role-Role=roleDao.findByName(roleName);
users.forEach(用户->{
user.addRole(角色);
创建(用户);
});
//其他一些行动
});
}
}

(当然,使用上述方法意味着只有一个层(在本例中为服务层)知道事务,因此必须始终从服务内部调用DAO)

捕获一个
持久性异常
然后回滚是没有意义的,
持久性异常
会自动导致回滚。他们,添加createAll应该在我的DAO中完成,对吗?我也有这个想法。如果我使用这个方法,我必须显式地打开一个连接,当然还有closi末端ng(通过is连接的锁销关闭或打开)。我将有多个服务和DAO。如果其中一个服务/DAO处理不当,我将有一个永无止境的事务,为什么我会避免这样做。我不确定我是否完全理解您的评论,但如果您有多个服务使用多个DAO,那么正确地进行编程事务管理是很困难的。我建议您仔细查看以声明方式处理事务的方法(使用Spring之类的框架,甚至是Spring之类的更轻量级的解决方案)此外,如果您坚持自己处理事务,请参阅我的更新答案我已尝试接管声明性事务管理。我尝试使用REST服务存储三个实体,最后一个实体必须导致回滚。不幸的是,前两个实体直接保存到DB中,无法撤消完整的事务。是否可能我必须将entitymanager传递给我的DAO吗?在不查看代码和不知道最终使用的库/框架的情况下,很难回答这个问题,但是如果您怀疑
RESOURCE\u LOCAL
事务没有正确启动,您可以通过检查
entitymanager.get的值来调试这个问题
public class UserService {

    private TransactionTemplate template;
    private RoleDao roleDao;
    private UserDao userDao; //make sure TransactionTemplate and all Daos use the same EntityManager - for a single transaction, at least

    public void saveUsers(Collection<User> users, String roleName) {
        template.executeInTransaction(() -> {
            Role role = roleDao.findByName(roleName);
            users.forEach(user -> {
                user.addRole(role);
                userDao.create(user);
            });
            // some other operations
        });
    }

}