【发布时间】:2016-07-29 15:24:36
【问题描述】:
我有一个带有 Hibernate 的 REST Spring Boot 应用程序。为简单起见,我们假设以下工作流程:
- 控制器处理传入请求,调用服务方法
- 服务方法为
@Transactional,做一些业务逻辑,调用Persistence方法 - 持久性方法由 DAO 对象处理,将内容保存到数据库中。
数据库对用户的username 有一个unique 约束。我现在的工作方式是这样的:
- 客户端向控制器发送请求
- 控制器调用服务
- 服务尝试通过 DAO 保存对象。如果出现
DataViolationException,Service 返回一个自定义的Exception - 控制器捕获自定义异常并发送回适当的响应
伪代码是这样的:
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 从事务中“冒泡”(而不是在服务中捕获它)。但这意味着 Controller 必须处理持久性异常,我不喜欢这样。
如果服务抛出“可理解的”异常供控制器处理,我更喜欢。该服务知道什么时候会出现持久性异常,并且能够将广泛的DataIntegrityViolationException“翻译”成有意义的。
有没有办法以这种方式处理异常?我并不特别喜欢使用“2 层服务层”来实现这一点的想法。
编辑:我想抛出自定义异常的另一个原因是编译器需要捕获它。我想强制控制器处理所有可能发生的异常。
【问题讨论】:
-
然后告诉
@Transactional它应该回滚那些异常。默认情况下它只回滚RuntimeExceptions。 -
您是否找到了一种方法来捕获 Service 而不是 Controller 中的异常?我正在考虑删除 @Transaction 并自己处理提交和回滚。
-
请尝试:@Transactional(noRollbackFor = DataIntegrityViolationException.class)
标签: java spring hibernate transactions