我有一个带有Hibernate的REST Spring启动应用程序。为简单起见,我们假设这个工作流程:
@Transactional
,执行一些业务逻辑并调用持久性方法数据库对用户的unique
有username
约束。我现在的工作方式是:
DataViolationException
,则Service返回自定义异常伪代码是:
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层服务层”来实现这一目标。
编辑:我想抛出自定义异常的另一个原因是编译器需要捕获它。我想强制执行控制器来处理可能发生的所有可能的异常。
答案 0 :(得分:0)
使用
注释您的服务方法content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FIMG_20190310_123752.jpg
如果抛出异常,它将告诉spring不提交事务,这样您就可以在控制器中捕获它
答案 1 :(得分:0)
您的存储库需要扩展JpaRepository,并且在执行此操作时。您可以从该存储库使用saveAndFlush方法。这意味着,您的代码将立即在数据库上执行,并且异常将在完成事务之前引发,并且您可以在Catch块中捕获它。
public class UserService {
@Transactional
public User createUser(...){
(...)
try{
userDAO.saveAndFlush(newUserObject);
} catch(DataIntegrityViolationException e){
throw new UserAlreadyExistsException(username);
}
}
}