I am using a org.springframework.data.jpa.repository.JpaRepository save method to save an entity. I figure that save method comes from CrudRepository interface. I am calling this save method from a service class.
try {
studentLog = studentsLogRepository.save(studentLog);
} catch (DataIntegrityViolationException dive) {
LOGGER.warn("Constraint violation occurred. Cannot insert the same record twice.", dive);
}
But the problem is DataIntegrityViolationException is not getting caugh in the catch block. Instead I see in the log following.
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]...
and
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
I even tried catching ConstraintViolationException which did not work. I thought spring data wraps data layer exception to DataAccessException, in this case its subclass DataIntegrityViolationException. Then why is the exception is not getting caught? My service method is not annotated with @Transactional
What is happening is that when calling the method .save(), under the hood Spring is telling the EntityManager to persist the entity, which will be only making it managed and persistent within the persistence context, however changes in your entity may not be immediately synchronized with the DB state (depending on the flush mode of your configuration), so either exceptions are not thrown yet, until flush or commit commands are issued. So you can try to call .saveAndFlush() to enforce DB synchronization. This way exceptions will be thrown immediately.
To further comprehend how Spring handles transaction management, I'll leave a useful link: Transaction Management
exception thrown from Spring exception translation mechanism when dealing with lower level persistence exceptions. so untill the transaction commits not done , so need to catch outside the scope
Example TODO Service Class
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);
or Use Global Exception Handler to do the same using controller advice
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With