Spring exception broadcasting mechanism not kicking
I have a scenario where I am deliberately trying to break unique constraint
while waiting for Spring DataIntegrityViolationException
, but that never happens.
javax.persistence.PersistenceException
thrown out with reason org.hibernate.exception.ConstraintViolationException
, but no Spring translation.
Classes DAO
and are Service
annotated correctly with the @Repository
and @Service
and @PersistenceContext
ed repository .
Services:
@Service
public class BookServiceImpl implements BookService {
@Inject private BookDAO bookDao;
@Transactional(propagation = Propagation.REQUIRED)
public Book createBook(Book book) {
Book bk = null;
try {
bk = bookDao.makePersistent(book);
} catch (AppDAOException e) {
throw new AppServiceException(e);
}
return bk;
}
}
My config:
<bean id="libmsEMF"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="libmsDS" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="libmsEMF" />
<property name="dataSource" ref="libmsDS" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="SQL_SERVER" />
<property name="showSql" value="false" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.SQLServer2008Dialect" />
</bean>
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
Exception trace:
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:289)
at com.sun.proxy.$Proxy60.persist(Unknown Source)
at com.hurontg.common.persistence.AbstractGenericDAOImpl.makePersistent(AbstractGenericDAOImpl.java:103)
... 57 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:129)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:211)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:96)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3032)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3558)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:98)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:490)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:195)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:214)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
... 64 more
Caused by: java.sql.SQLException: Violation of UNIQUE KEY constraint 'UK_AUTHOR_TITLE'. Cannot insert duplicate key in object 'dbo.BOOK'. The duplicate key value is (Jim Corbett, The Temple Tiger).
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:372)
at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2886)
at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2328)
at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:638)
at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:614)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:573)
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:707)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.jdbc.pool.interceptor.AbstractQueryReport$StatementProxy.invoke(AbstractQueryReport.java:235)
at com.sun.proxy.$Proxy70.executeUpdate(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.jdbc.pool.interceptor.AbstractQueryReport$StatementProxy.invoke(AbstractQueryReport.java:235)
at com.sun.proxy.$Proxy70.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
... 85 more
source to share
Probably the problem is that you don't have any PersistenceExceptionTranslator beans in your context that can unpack Hibernate JPA Persistence exceptions to find out what the reason is.
Try adding HibernateJpaDialect bean to your application context:
In Java
@Bean
public HibernateJpaDialect hibernateJpaDialect() {
return new HibernateJpaDialect();
}
Or in XML
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
Hibernate AbstractEntityManagerImpl transfers Hibernate exceptions to JPA exceptions before Spring translates it. HibernateJpaDialect implements the Spring PersistenceExceptionTranslator interface and knows how to deploy these PersistenceExceptions.
source to share
As I said, I had the same problem a couple of days ago. At least in my situation / confguration I solved the problem by using / implementing the PersistenceExceptionTranslationPostProcesor bean .
It can be contextualized in such a way
XML
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
JAVA
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
Even though the documentation states the following, I have not been able to confirm that LocalSessionFactoryBean
for Hibernate4
also implements this bean out of the box (I'm guessing it's a matter of diving into the code).
All Spring applicable resource factories (like LocalContainerEntityManagerFactoryBean) implement the PersistenceExceptionTranslator interface out of the box. As a consequence, all that is usually needed to enable automatic exclusion, the translation marks all affected beans (such as repositories or DAOs) with the @Repository annotation, along with defining this post processor as a bean in the application context.
source to share