Java 在@Transactional service方法中捕获DataIntegrityViolationException
我有一个带Hibernate的REST Spring启动应用程序。为简单起见,让我们假设此工作流:Java 在@Transactional service方法中捕获DataIntegrityViolationException,java,spring,hibernate,transactions,Java,Spring,Hibernate,Transactions,我有一个带Hibernate的REST Spring启动应用程序。为简单起见,让我们假设此工作流: 控制器处理传入请求,调用服务方法 服务方法是@Transactional,执行一些业务逻辑并调用持久性方法 持久化方法由DAO对象处理,将内容保存到数据库中 数据库对用户的username具有unique约束。我现在的工作方式是: 客户端向控制器发送请求 控制器呼叫服务 服务尝试通过DAO保存对象。如果发生DataViolationException,服务将返回自定义异常 控制器捕获自定义异常并发
@Transactional
,执行一些业务逻辑并调用持久性方法username
具有unique
约束。我现在的工作方式是:
DataViolationException
,服务将返回自定义异常伪代码如下所示:
public class UserController {
@RequestMapping("/user")
public User createUser(...){
try{
return userService.createUser(...);
} catch (UserAlreadyExistsException e){
// Do some processing and return error message to client
}
}
}
public class UserService {
@Transactional
public User createUser(...){
(...)
try{
userDAO.save(newUserObject);
} catch(DataIntegrityViolationException e){
throw new UserAlreadyExistsException(username);
}
}
}
然而,这样,当试图创建重复用户时,我会得到一个错误
javax.persistence.RollbackException: Transaction marked as rollbackOnly
解决此问题的一种方法似乎是让DataIntegrityViolationException
从事务中“冒泡”(而不是在服务中捕捉它)。但这意味着控制器必须处理持久性异常,我不喜欢这样
我更喜欢服务抛出“可理解”的异常,以便控制器处理。该服务知道预期的持久性异常以及何时发生,并且能够将广泛的DataIntegrityViolationException
转换为有意义的异常
有没有一种方法可以这样处理异常?我并不特别喜欢使用“两层服务层”来实现这一点
编辑:我想抛出自定义异常的另一个原因是编译器需要捕获它。我想强制控制器处理所有可能发生的异常。用
@Transactional(rollbackFor = UserAlreadyExistsException.class)
如果抛出异常,它会告诉spring不要提交事务,这样您就可以在控制器中捕获它了。您的存储库需要扩展JpaRepository,当您这样做时。您可以使用该存储库中的saveAndFlush方法。这意味着,您的代码将立即在数据库上执行,异常将在事务完成之前抛出,您将能够在catch块中捕获它。我还添加了用于删除操作的示例
public class UserService {
@Transactional
public User createUser(...){
(...)
try{
userDAO.saveAndFlush(newUserObject);
} catch(DataIntegrityViolationException e){
throw new UserAlreadyExistsException(username);
}
}
@Transactional
public void deleteUser(...){
(...)
try{
userDAO.delete(deletingUserObject);
userDAO.flush();
} catch(DataIntegrityViolationException e){
throw new UserException(username);
}
}
}
然后还告诉
@Transactional
,它应该为这些异常回滚。默认情况下,它只为运行时异常
s回滚。您是否找到了在服务中而不是在控制器中捕获异常的方法?我正在考虑删除@Transaction,自己处理提交和回滚。请尝试:@Transactional(norollboor=DataIntegrityViolationException.class)了解哪个约束被破坏的最好方法是什么,例如,如果一个实体上有多个约束?或者不同实体上的约束?没错,如果我有两个唯一的约束,如何区分它们?