当我想使用find()方法两次时,我可以使用flush()而不是commit()吗?

时间:2017-05-20 16:43:37

标签: java hibernate jpa

我想知道用户名是否已被使用,如果不是这样,那么是否已经使用了电子邮件地址。我不想为每个实体管理器查找方法开始并提交新事务,因为我认为只使用一个事务进行多个操作比使用多个操作更有效。我可以在我的方法中用commit()替换commit()吗?

    public void createUser(User_ newUser){
            UserDao userDao = new UserDao();
    Alert alert;
    EntityTransaction transaction = entityManager.getTransaction();

        try{
            transaction.begin();
            userDao.find("userName",newUser.getUserName());
            transaction.commit();
            alert = new Alert(Alert.AlertType.ERROR,"Username already in use", ButtonType.OK);
            alert.showAndWait();
            if (alert.getResult() == ButtonType.OK)alert.close();
        }        
        catch(NoResultException e){
            try{
                transaction.begin();
                userDao.find("emailAdress",newUser.getEmailAdress());
                transaction.commit();
                alert = new Alert(Alert.AlertType.ERROR,"E-mail adress already in use", ButtonType.OK);
                alert.showAndWait();
                if (alert.getResult() == ButtonType.OK) alert.close();             
                }
            catch(NoResultException x){
                    transaction.begin();
                    userDao.save(newUser);
                    transaction.commit();
                }
        }
        catch(RuntimeException e){
            transaction.rollback();    
        }
        finally{entityManager.close();}
} 
谢谢。

2 个答案:

答案 0 :(得分:1)

您的代码有三个问题:

  1. 为什么你甚至将查询方法包装在单独的事务中?首先,执行查询不需要一个。其次,你是正确的尝试用单个事务包装你的查询方法,但出于错误的原因。这与性能几乎没有关系,与隔离有关。这里只需要一个事务来阻止对createUser的另一个调用在这两个查询之间创建具有相同用户名的用户(显然,出于同样的原因,持久化用户应该是同一事务的一部分)。

  2. 您应该避免使用异常来处理应用程序的正常状态。这不仅是使用异常的正确方法,而且就事务状态而言,您也会遇到更少的问题。从你期望userDao.find抛出NoResultException的事实来看,我假设它在内部使用query.getSingleResult()。只有当您希望查询始终具有结果时,才应使用getSingleResult。您应该使用getResultList()代替,并进行空洞检查,或者更好地查询具有给定用户名的User实体的 count

  3. 您的方法是混合业务逻辑和表示问题。将数据保存到数据库并显示警报绝对不应该在单个方法中完成。如果您绝对需要使用保留数据的相同方法将错误传达给用户,请确保在>提交事务后执行,以防止它超时。

答案 1 :(得分:0)

一旦commit()成功,就无法回滚事务。刷新是将底层持久存储与内存中保持的持久状态同步的过程。它将在正在运行的事务中更新或插入到表中,但它可能不会提交这些更改。

flush()将使数据库与内存中保存的对象/对象的当前状态同步,但不会提交事务。因此,如果在调用flush()之后出现任何异常,那么事务将被回滚。您可以使用flush()将数据库与小块数据同步,而不是使用commit()一次提交大数据,并面临获得内存不足的风险。

commit()将使数据库中存储的数据永久化。一旦commit()成功,就无法回滚事务。

现在,您的业务逻辑应该使用哪一个