Spring Data - 无法在服务层中捕获DataIntegrityViolationException

时间:2016-12-28 13:11:31

标签: java spring hibernate spring-data spring-data-jpa

我正在使用org.springframework.data.jpa.repository.JpaRepository存储方法来保存实体。我认为save方法来自CrudRepository接口。我从服务类调用这个save方法。

try {
    studentLog = studentsLogRepository.save(studentLog);        
} catch (DataIntegrityViolationException dive) {
    LOGGER.warn("Constraint violation occurred. Cannot insert the same record twice.", dive);
}

但问题是DataIntegrityViolationException在catch区块中没有出现问题。相反,我在后面的日志中看到。

java.sql.BatchUpdateException: ORA-00001: unique constraint (QA_VPP.UX_TVPPC_TRAN_LOG_1) violated
        at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10296) ~[ojdbc6-11.2.0.2.0.jar:11.2.0.2.0]
        at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:216) ~[ojdbc6-11.2.0.2.0.jar:11.2.0.2.0]
        at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) ~[commons-dbcp-1.3.jar:1.3]
        at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) ~[commons-dbcp-1.3.jar:1.3]
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]...

2016-12-28 10:13:52,655 LL="DEBUG" CR="1_1482920032_407_357_l73q069_VPP" RE="1482920032407" DE="1" TR="tomcat-http--12" LN="o.s.o.j.JpaTransactionManager"  Initiating transaction rollback after commit exception
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
        at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321) ~[spring-orm-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:121) ~[spring-orm-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ~[spring-orm-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at 

我甚至尝试捕获不起作用的ConstraintViolationException。我认为spring数据将数据层异常包装到DataAccessException,在这种情况下是它的子类DataIntegrityViolationException。那为什么异常没有被抓住?我的服务方法未使用@Transactional

进行注释

2 个答案:

答案 0 :(得分:1)

当处理较低级别的持久性异常时,Spring异常转换机制抛出的

exception。 因此,直到事务提交未完成为止,因此需要在范围之外进行捕获

示例TODO 服务等级

studentLog = studentsLogRepository.save(studentLog);        

Catch at controller class
try {
    call student service     
} catch (DataIntegrityViolationException dive) {
    LOGGER.warn("Constraint violation occurred. Cannot insert the same record twice.", dive);

或使用全局异常处理程序通过控制器建议执行相同操作

答案 1 :(得分:0)

正在发生的事情是,在调用方法.save()时,Spring告诉EntityManager持久化实体,这只会使它在持久性上下文中得到管理和持久化。实体中的更改可能不会立即与数据库状态同步(取决于配置的刷新模式),因此,直到发出flush或commit命令之前,都不会引发任何异常。因此,您可以尝试调用.saveAndFlush()来强制执行数据库同步。这样,异常将立即引发。

为了进一步理解Spring如何处理事务管理,我将留下一个有用的链接:Transaction Management