我有一个带有 Hibernate 的 REST Spring 启动应用程序。为简单起见,我们假设此工作流程:
@Transactional
, 做一些业务逻辑并调用 Persistence 方法 数据库有一个
unique
对 username
的约束用户的。我现在的工作方式是这样的: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
从事务中“冒泡”(而不是在服务中捕获它)。但这意味着 Controller 必须处理持久性异常,我不喜欢那样。我更喜欢服务抛出“可理解”的异常以供 Controller 处理。该服务知道预期什么持久性异常以及何时发生,并且能够“翻译”广泛的
DataIntegrityViolationException
变成一个有意义的。有没有办法以这种方式处理异常?我不是特别喜欢使用“2 层服务层”来实现这一点的想法。
编辑:我想抛出自定义异常的另一个原因是编译器需要捕获它。我想强制 Controller 处理所有可能发生的异常。
最佳答案
您的存储库需要扩展 JpaRepository,当您这样做时。您可以使用该存储库中的 saveAndFlush 方法。这意味着,您的代码将立即在数据库上执行,并在完成事务之前抛出异常,您将能够在 Catch 块中捕获它。我还添加了用于删除操作的示例。
存储库:
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserDAO extends JpaRepository<User, Long> {
}
服务: public class UserService {
private UserDAO userDAO;
(...)
@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);
}
}
}
关于java - 在@Transactional 服务方法中捕获 DataIntegrityViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36498327/