无法捕捉由约束条件违反引起的Hibernate异常。

3

我浏览了很多其他关于未捕获异常的问题(包括无法捕获ConstraintViolationException),但没有一个与我的问题相同。

使用RestEasy进行网络连接,Hibernate与Postgres数据库链接。

我有一个对象:

@Entity
@Table(uniqueConstraints={@UniqueConstraint(columnNames={"user_id"})})
public class Outcome {

    @Id
    @GeneratedValue
    private Long id;

    @OneToOne
    private User user;

    private String anotherAttribute;
}

OutcomeResource.saveOutcome会向DB服务发送一个结果(Outcome):

@POST
@Consumes("application/json")
@Transactional
public Response saveOutcome(Outcome outcome){
    try {
        myRepository.save(outcome);
        return Response.ok().build();
    } catch (Exception e) {
        System.out.println("I caught the exception:" + e);
        return Response.status(Response.Status.BAD_REQUEST).build();
    }
}

然后通过OutcomeRepository.save将其持久化到数据库中:

public void save(Outcome outcome) {
    try {
        getEntityManager().persist(outcome);
    } catch (Exception e) {
        System.out.println("No I caught the exception : " + e);
    }
}
当第一个结果被发布并保存到用户时,它会成功保存在数据库中。如果发布第二个结果,则会抛出错误,这是预期的。 缩短的错误堆栈跟踪如下:
javax.persistence.RollbackException: 
   Error while committing the transaction
   Description: The server encountered an unexpected condition that
   prevented it from fulfilling the request.
   Exception: org.jboss.resteasy.spi.UnhandledException:
   javax.persistence.RollbackException: Error while committing the transaction
org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:78)...
Root cause: javax.persistence.RollbackException: 
    Error while committing the transaction...
Root cause: javax.persistence.PersistenceException:
    org.hibernate.exception.ConstraintViolationException: 
    could not execute statement...
Root cause: org.hibernate.exception.ConstraintViolationException: 
    could not execute statement...
Root cause: postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint
    Detail: Key (user_id)=(361) already exists.
我希望能够捕获此错误并返回一个糟糕的请求响应。尽管尝试捕获通用异常和堆栈跟踪中的每种特定类型的异常,但两个catch块都没有被执行。 为什么两种方法都无法捕获异常?如何才能够实现呢?

不是 EntityManager 抛出了异常,而是事务。 - kaiser
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2
经过数小时的研究,我发现无法捕获异常,因为它是在方法完成后抛出的。这是因为服务层方法被标记为@Transactional,所以直到该事务结束,Hibernate才会抛出异常。 如果使用Spring:编写一个after-throwing建议,将转换异常显然允许您处理此问题,但我尚未测试过。 我没有找到一种方法来处理Guice中的此异常,因此将其保留未处理。在我的情况下,这是可以接受的。 好的信息来源:http://forum.spring.io/forum/spring-projects/data/68995-transaction-manager-appears-to-be-eating-the-runtime-exception

或者另一种方法是,您可以将@TransactionalOutComeResource.save..方法进一步移动到存储库,并且这样您应该能够在OutComeResponse.save...方法中捕获异常。 - Madhusudana Reddy Sunnapu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,