Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在@Transactional service方法中捕获DataIntegrityViolationException_Java_Spring_Hibernate_Transactions - Fatal编程技术网

Java 在@Transactional service方法中捕获DataIntegrityViolationException

Java 在@Transactional service方法中捕获DataIntegrityViolationException,java,spring,hibernate,transactions,Java,Spring,Hibernate,Transactions,我有一个带Hibernate的REST Spring启动应用程序。为简单起见,让我们假设此工作流: 控制器处理传入请求,调用服务方法 服务方法是@Transactional,执行一些业务逻辑并调用持久性方法 持久化方法由DAO对象处理,将内容保存到数据库中 数据库对用户的username具有unique约束。我现在的工作方式是: 客户端向控制器发送请求 控制器呼叫服务 服务尝试通过DAO保存对象。如果发生DataViolationException,服务将返回自定义异常 控制器捕获自定义异常并发

我有一个带Hibernate的REST Spring启动应用程序。为简单起见,让我们假设此工作流:

  • 控制器处理传入请求,调用服务方法
  • 服务方法是
    @Transactional
    ,执行一些业务逻辑并调用持久性方法
  • 持久化方法由DAO对象处理,将内容保存到数据库中
  • 数据库对用户的
    username
    具有
    unique
    约束。我现在的工作方式是:

  • 客户端向控制器发送请求
  • 控制器呼叫服务
  • 服务尝试通过DAO保存对象。如果发生
    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)了解哪个约束被破坏的最好方法是什么,例如,如果一个实体上有多个约束?或者不同实体上的约束?没错,如果我有两个唯一的约束,如何区分它们?