1

I've enabled my spring application to use transactions and annotated my service method accordingly but the changes to my DB persist when a RuntimeException is thrown.

My Spring configuration looks like this:

<!-- Data Source. -->   
<jee:jndi-lookup id="dataSource" jndi-name="java:/jdbc/BeheermoduleDS"/>

<!-- JPA Entity Manager. -->    
<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/jpa/BeheermoduleDS"/>

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />

My datasource configuration in my jboss' configuration file looks like this:

<datasource jta="true" jndi-name="java:/jdbc/BeheermoduleDS" pool-name="BeheermoduleDS" enabled="true" use-java-context="true" use-ccm="true">
    <connection-url>jdbc:sqlserver://localhost:1433;databaseName=Gebruikers;</connection-url>
    <driver>sqljdbc</driver>
    <security>
        <user-name>jboss</user-name>
        <password>*****</password>
    </security>
</datasource>

My Service method looks like this:

@Transactional
public void authorise(Gebruiker user) {

    user.setStatus(GebruikerStatus.Actief.name());
    gebruikerRepo.save(user);
    if (true) {
        throw new RuntimeException("Exception happened just like that");
    }

    // does more stuff here that is never reached
}

My repository extends a spring data repository and looks like this:

public interface GebruikerRepository extends PagingAndSortingRepository<Gebruiker, Long>, QueryDslPredicateExecutor<Gebruiker> {

}

The transaction is thrown and caught by a controller which just shows a message to the user that an exception occurred. When I check my SQL Server DB, the change made to the user status have been commited.

Weren't they supposed to have been rolled back with the RuntimeException?

After turning debug on for org.springframework.transaction.interceptor I saw that no transactions are being started for my service method, but they are for a bunch of JpaRepository methods.

Also, this is how my persistence.xml looks like:

<persistence-unit name="BeheermodulePU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <non-jta-data-source>java:/jdbc/BeheermoduleDS</non-jta-data-source> 
Henrique Ordine
  • 3,337
  • 4
  • 44
  • 70
  • For more clarity can you paste the Controller code? I assume the controller code does not have @Transactional annotations. – Andy Dufresne Dec 24 '14 at 06:01
  • No, I didn't annotate it with &Transanction. It has @Controller and &Request annotations only. – Henrique Ordine Dec 24 '14 at 14:07
  • Stackoverflow doesn't allow me to use more than one @ per post, by the way. – Henrique Ordine Dec 24 '14 at 14:16
  • It is very strange that the transactions are not rolled back. Can you confirm that the transactions are really getting applied by 1. Debugging and verifying that the code reaches TransactionInterceptor class and 2. Using a SQL Profiler to see if the "begin tran" statement is executed. – Andy Dufresne Dec 24 '14 at 17:06
  • Yes, thanks for the tip. I turned debug on for the interceptor and I get a bunch of starting/completing transaction for SimpleJpaRepository.findOne methods but I don't see anything being logged for my method. – Henrique Ordine Dec 25 '14 at 14:22
  • Could it be that transactions are turned on at the JPA repository level but not at the service level? Maybe I should set another class as the transaction manager, other than JpaTransactionManager? – Henrique Ordine Dec 25 '14 at 14:27
  • Are your services and `tx:annotation-driven` in the same context? Make sure you aren't scanning for the same components twice (which is what it looks like you are doing) leading to a non transactional (non proxied) service. – M. Deinum Dec 29 '14 at 09:32
  • Why does it look like I'm doing that? I have these two tags in my spring config file: and then I annotated my service with org.springframework.stereotype.Service – Henrique Ordine Dec 29 '14 at 12:12
  • Wait, I found the same annotation in another file, I'll remove it and test this again. Keep you posted. – Henrique Ordine Dec 29 '14 at 12:21
  • Yes, it seems that was the problem. I changed the declarations to how they suggest here: http://stackoverflow.com/questions/4333390/service-are-constructed-twice and it works now. @M.Deinum Do you want to create an answer for this question? otherwise I'll do it myself. – Henrique Ordine Dec 29 '14 at 13:05
  • @HenriqueOrdine It looks like that due to the errors you get and you wouldn't be the first nor the last doing duplicate component scanning (without realizing that). – M. Deinum Dec 29 '14 at 13:59

1 Answers1

3

Judging from the symptoms you describe you are scanning for the same classes twice. You probably have the same <context:component-scan /> in both the configuration of the ContextLoaderListener and DispatcherServlet.

You want the ContextLoaderListener to scan for everything but @Controller and the DispatcherServlet only for @Controllers. Leading to something like this.

For the ContextLoaderListener

<!-- Load everything except @Controllers -->
<context:component-scan base-package="com.myapp">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

For the DispatcherServlet

<!-- Load everything except @Controllers -->
<context:component-scan base-package="com.myapp" use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

See also @Service are constructed twice for another sample and broader explanation.

Community
  • 1
  • 1
M. Deinum
  • 115,695
  • 22
  • 220
  • 224