I got this problem for a while and can't figure out what I am doing wrong. Here is the context:
- Spring 4.3.4.RELEASE
- Spring-data-jpa 1.10.6.RELEASE
- Hibernate 5.2.5.Final
- I'm using wildfly 10, starting via maven plugin
- configured datasource for JNDI lookup correctly
- using spring-data with @Repository on interfaces
- created entityManagerFactory as a spring bean (LocalContainerEntityManagerFactoryBean)
- as for transaction manager, I tried to use both 'tx:jta-transaction-manager' and spring bean (JtaTransactionManager)
- configured persistence.xml
- enable 'tx:annotation-driven'
So, I got a @Service class (SistemaBOImpl) that has a @Repository injected (SistemaDAO) and a test method for transactional behavior:
@Service
@Transactional(propagation = Propagation.SUPPORTS)
public class SistemaBOImpl extends AbstractBO<Sistema, Long> implements SistemaBO {
@Autowired
public SistemaBOImpl(SistemaDAO sistemaDAO) {
super(sistemaDAO);
}
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { BusinessException.class })
public void testTrans() throws BusinessException {
try {
final Sistema s = findOne(1L);
s.setCodUsuAlt(SimpleDateFormat.getInstance().format(new Date()));
s.setDatAlt(new Date());
save(s); //1st save
save(new Sistema()); //2nd save
} catch (Exception e) {
throw new RuntimeException(e);
// throw new BusinessException(e);
}
}
}
DAO
@Repository
@Transactional
public interface SistemaDAO extends DAO<Sistema, Long>, JpaRepository<Sistema, Long> {}
The problem is: Although 2nd save won't complete due to database constraints (and I did it on purpose, 1st save is commited and data is changed. I can't figure out why it is not rolling back all. What am I doing wrong?!?
Here are my other config file:
applicationContext.xml
<beans ... ommited namespace hell>
<context:annotation-config />
<context:component-scan base-package="br.com.myco" />
<tx:jta-transaction-manager />
<tx:annotation-driven transaction-manager="transactionManager" />
<jpa:repositories base-package="br.com.myco" />
<jee:jndi-lookup id="dataSource" jndi-name="java:jboss/datasources/Myco_DB" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="dataSource" />
<property name="jpaVendorAdapter" >
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="persistenceUnitName" value="tof"/>
<property name="packagesToScan" value="br.com.myco.tof"/>
</bean>
persistence.xml
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">
<persistence-unit name="myco" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/Myco_DB</jta-data-source>
<class>br.com.abril.tof.domain.Sistema</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
</properties>
</persistence-unit>
web.xml
<web-app version="3.1" ...>
<display-name>MyCO</display-name>
<description>MyCO</description>
<!-- Carrega Spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>myco</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myco</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<persistence-unit-ref>
<persistence-unit-ref-name>jpa/EntityManager</persistence-unit-ref-name>
<persistence-unit-name>myco</persistence-unit-name>
</persistence-unit-ref>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
Log/Stacktrace for 2nd save
Caused by: org.hibernate.HibernateException: Could not apply work
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doTheWorkInNewTransaction(JtaIsolationDelegate.java:112)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.delegateWork(JtaIsolationDelegate.java:65)
at org.hibernate.id.enhanced.TableStructure$1.getNextValue(TableStructure.java:125)
at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40)
at org.hibernate.id.enhanced.SequenceStyleGenerator.generate(SequenceStyleGenerator.java:412)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
at com.sun.proxy.$Proxy63.persist(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy63.persist(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:506)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
**at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)**
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 65 more
Got it folks!
After debugging for, like, a lot and searching for flaws on transaction configurations, I ended up seeing that all my Business weren't proxies. Well, that said I thought that it should be spring configuring my beans the issue and, for god sake :), was it. I got this spring-mvc config done wrong (WEB-INF/myco-servlet.xml):
See the base-package? It was pointing to the same packages as in my applicationContext.xml:
I just had to change that config in myco-servlet.xml to the main mvc package:
And worked just fine!
Kudos for this question on stackoverflow also for the enlightment about the issue.
Check if the MySQL engine you are using is InnoDB. If you are using MyISAM, transaction is not supported.