Spring - 无法捕获ConstraintViolationException

时间:2017-07-14 10:13:40

标签: spring spring-data spring-data-jpa

我的服务方法有:

@Transactional
    public MyResponse create(UserCredentials cred) {
        User user = new User(cred);
        try {
            final User created = userRepository.save(user);
            return new MyResponse(user, "Created");
        } catch (TransactionSystemException e) {
            return new MyResponse(null, "Cannot create");
        } catch (ConstraintViolationException e) {
            return new MyResponse(null, "Cannot create");
        }
    }

用户类:

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(
            name = "id",
            updatable = false,
            nullable = false
    )
    private Long id;

    @NotBlank
    @Column(
            nullable = false,
            unique = true
    )
    private String username;

    @NotBlank
    @Column(
            nullable = false,
            unique = true
    )
    private String email;

    @NotBlank
    @Column(nullable = false)
    private String password;

问题是当我发送JSON空用户名或空电子邮件时。当我调试应用程序时,我得到ConstraintViolationExcpetion,但在JSON响应中,我得到:

{
    "timestamp": 1500026388864,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "org.springframework.transaction.TransactionSystemException",
    "message": "Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly",
    "path": "/register"
}

调试器在catch(ConstraintViolationException e)停止,但最后我得到SystemTransactionException,为什么?

2 个答案:

答案 0 :(得分:2)

抓住上述例外情况。在使用@Transactional注释的方法之外。

在您的情况下,您拦截异常并吞下但DB状态仍然不正确。因此,在注释方法退出后尝试提交它失败。

或添加ExceptionHandler以捕获此异常并返回正确的响应。

答案 1 :(得分:1)

  

调试器在catch(ConstraintViolationException e)停止,但最后我得到SystemTransactionException,为什么?

这是由于Spring的异常转换机制,Spring将其中一个基础异常包装在其自己的RuntimeException类中。

起初看起来很奇怪,但对基础JPA提供程序甚至更改数据库的更改可以(通常)针对相同的故障条件抛出不同的异常类型。

  • 您只需要担心处理Spring异常,而不是担心底层技术可能抛出的异常范围
  • 已检查的异常会映射到未经检查的异常,因此您不必使用try-catch块来编写代码。
  • 将异常转换为服务器响应代码更容易(在您的情况下,转换为500是自动的)。

希望这有帮助。

[afterthought] 值得一提的是,Spring将执行此翻译之后它会调用您的事务方法,这就是为什么你永远不会抓住{{1 }}