(Transaction not rolling back) Spring-data, JTA, JPA, Wildfly10
Asked Answered
E

2

1

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
Exhume answered 17/1, 2017 at 23:54 Comment(4)
You have rollbackFor = BusinessException.class but are throwing a RuntimeException in case of an error. The automatic rollback will take place only if the method throws a BusinessException, which it does not, so the rollback does not take place (as expected).Khalid
Hi manish, I know that, it was just one of many tests I've made. I tried: ommiting the 'rollbackFor' config and throw both exceptions, I tried putting Runtime and BusinessException on that config and so on...Exhume
Can you debug your application to see if transactions are actually being started for the test? You can put breakpoints in TransactionInterceptor to check this. The interceptor intercepts calls to the proxy generated for the Spring managed bean. With your Spring configuration (specifically <tx:jta-transaction-manager />), the proxy will be an instance of SistemaBO (because the default proxies are JDK proxies which proxy interfaces not classes). So, unless SistemaBO declares a testTrans method with @Transactional, there may not be a transaction running when the test runs.Khalid
I updated the question with the stacktrace for the 2nd save and it DOES pass in TransactionInterceptor (I marked between ) **at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)Exhume
E
0

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):

<context:component-scan base-package="br.com.myco" />
<mvc:annotation-driven />

See the base-package? It was pointing to the same packages as in my applicationContext.xml:

<context:component-scan base-package="br.com.myco" />

I just had to change that config in myco-servlet.xml to the main mvc package:

<context:component-scan base-package="br.com.myco.service" />

And worked just fine!

Kudos for this question on stackoverflow also for the enlightment about the issue.

Exhume answered 16/2, 2017 at 18:10 Comment(0)
P
0

Check if the MySQL engine you are using is InnoDB. If you are using MyISAM, transaction is not supported.

Pregnant answered 18/1, 2017 at 1:42 Comment(3)
Hi Quincy, I'm using InnoDB.Exhume
So is the engine you using supports transaction?Pregnant
Well, as I'm using InnoDB... transaction is supported. Also, I assured that MySQL autocommit is set to FALSE.Exhume
E
0

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):

<context:component-scan base-package="br.com.myco" />
<mvc:annotation-driven />

See the base-package? It was pointing to the same packages as in my applicationContext.xml:

<context:component-scan base-package="br.com.myco" />

I just had to change that config in myco-servlet.xml to the main mvc package:

<context:component-scan base-package="br.com.myco.service" />

And worked just fine!

Kudos for this question on stackoverflow also for the enlightment about the issue.

Exhume answered 16/2, 2017 at 18:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.