我想知道用户名是否已被使用,如果不是这样,那么是否已经使用了电子邮件地址。我不想为每个实体管理器查找方法开始并提交新事务,因为我认为只使用一个事务进行多个操作比使用多个操作更有效。我可以在我的方法中用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();}
}
谢谢。
答案 0 :(得分:1)
您的代码有三个问题:
为什么你甚至将查询方法包装在单独的事务中?首先,执行查询不需要一个。其次,你是正确的尝试用单个事务包装你的查询方法,但出于错误的原因。这与性能几乎没有关系,与隔离有关。这里只需要一个事务来阻止对createUser
的另一个调用在这两个查询之间创建具有相同用户名的用户(显然,出于同样的原因,持久化用户应该是同一事务的一部分)。
您应该避免使用异常来处理应用程序的正常状态。这不仅是使用异常的正确方法,而且就事务状态而言,您也会遇到更少的问题。从你期望userDao.find
抛出NoResultException
的事实来看,我假设它在内部使用query.getSingleResult()
。只有当您希望查询始终具有结果时,才应使用getSingleResult
。您应该使用getResultList()
代替,并进行空洞检查,或者更好地查询具有给定用户名的User
实体的 count
您的方法是混合业务逻辑和表示问题。将数据保存到数据库并显示警报绝对不应该在单个方法中完成。如果您绝对需要使用保留数据的相同方法将错误传达给用户,请确保在>>提交事务后执行,以防止它超时。
答案 1 :(得分:0)
一旦commit()成功,就无法回滚事务。刷新是将底层持久存储与内存中保持的持久状态同步的过程。它将在正在运行的事务中更新或插入到表中,但它可能不会提交这些更改。
flush()将使数据库与内存中保存的对象/对象的当前状态同步,但不会提交事务。因此,如果在调用flush()之后出现任何异常,那么事务将被回滚。您可以使用flush()将数据库与小块数据同步,而不是使用commit()一次提交大数据,并面临获得内存不足的风险。
commit()将使数据库中存储的数据永久化。一旦commit()成功,就无法回滚事务。
现在,您的业务逻辑应该使用哪一个