1

I can only get an active programmatic transaction in my spring (3.0.5) jdbc application, running on Oracle 11.2, when the txAdvice points to the actual method (mainTest()) called from the application context (example "AAA" below). If the txAdvice points to a child method (transactionTest()) of mainTest() (example "BBB" below) then I no longer have an active transaction.

Relevant code:

public class MainDS {
    public static Controller cont;
    public static void main(String[] args) {

        String [] configList ={"spring.xml"};

        ApplicationContext ctx = new ClassPathXmlApplicationContext(configList);
        cont = (Controller)ctx.getBean("controller");
        cont.mainTest();     
    }
}

public class Controller {
    private JdbcTemplate jdbcTemplate;  

    public void mainTest()
    {
        transactionTest();
        // MainDS.cont.transactionTest(); // also does not work
    }

    public void transactionTest(){
        try {
            // This prints "Transaction active = true" for AAA but "Transaction active = false"  for BBB
            System.out.println("Transaction active = " + TransactionSynchronizationManager.isActualTransactionActive() );

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

and my spring.xml file is:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">


<bean id="controller" class="Controller">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>


<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="main*" propagation="REQUIRED" />       <!-- AAA -->
        <tx:method name="transaction*" propagation="REQUIRED" />    <!-- or BBB -->
    </tx:attributes>
</tx:advice>



<aop:config>    
    <aop:pointcut id="myMethods" expression="execution(* *..Controller.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="myMethods" />
</aop:config>



<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="dataConfigPropertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="searchSystemEnvironment" value="true" />
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="initialSize" value="2" />
    <property name="maxActive" value="2" />

    <property name="url" value="my connection details" />
    <property name="username" value="xxx" />
    <property name="password" value="xxx" />
</bean>

</beans>

How do I get an active transaction for option BBB. Any ideas very welcome.

Regards DS

DS.
  • 604
  • 2
  • 6
  • 24

1 Answers1

2

"BBB" case: the "mainTest()" method calls directly the "transactionTest()" method, omitting the aspect.

If you want to invoke the dynamically created proxy of the "transactionTest()" method, I suppose, you could do it through self bean reference (injected). Also as far as I remember, the spring manual used to suggest to call such methods via interface references (again using injected interface references).

Note: this is a really bad design! Implementation example (per request):

<bean id="controller" class="test.Controller">
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
    <property name="instance" ref="controller" />
</bean>

public class Controller {
    private JdbcTemplate jdbcTemplate;
    private Controller instance;

    public void mainTest() {
        instance.transactionTest();
    }

    public void transactionTest() {
        System.out.println("Transaction active = " + TransactionSynchronizationManager.isActualTransactionActive() );
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public Controller getInstance() {
        return instance;
    }

    public void setInstance(Controller instance) {
        this.instance = instance;
    }
}

Transaction active = true

This behaviour is well documented in the spring manual (I recall it in the Aspects section), so you should definitely read it: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/aop.html section 9.6.1

More over, this question has already been covered here: One Service method invoke inner multiple method for Spring transaction

Community
  • 1
  • 1
Ivan
  • 837
  • 6
  • 15
  • Thanks for the link, its similar to what im doing but not the same. They want 2 transactions ie what I want is all methods in the Controller() class begining with trans* to be in their own transaction. Can you please explain how to do "self bean reference" – DS. Sep 15 '14 at 09:48
  • I changed the call to transactionTest() to: MainDS.cont.transactionTest(); to use the ApplicationContext, but there was still no transaction in transactionTest() – DS. Sep 15 '14 at 10:59
  • Thats what i suspected you meant and i agree , it's bad design. I tried it however since im stuck, but it didn't work, still no transaction. I think that: MainDS.cont.transactionTest(); should probably be the solution but that also doesn't work but i don't understand why not. – DS. Sep 15 '14 at 12:38
  • Hm, are you stuck with 3.0.5? You should try upgrading to the latest spring 3 release and see results. May be you've missed something obvious, but both solutions do work with the latest spring on my PC. And ofc. I wouldn't exclude some bug / specifics of the 3.0.5 version. – Ivan Sep 15 '14 at 12:42
  • I've tried 3.0.5 - both solutions do work. Double check everything. – Ivan Sep 15 '14 at 13:05
  • I've also tried 4.0.6 and it doesn't work. I've been double checking everything for several days, im sure i've done something stupid but i just can't see what. – DS. Sep 15 '14 at 13:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/61279/discussion-between-ivan-and-ds). – Ivan Sep 15 '14 at 13:44