Announcement Announcement Module
Collapse
No announcement yet.
Problems with Spring JDBC Transaction Management Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problems with Spring JDBC Transaction Management

    Hi All,
    I have used spring aop for transaction management with hibernate and jdbc. With hibernate the tx management is working fine and the database transaction is rolled back when a particular exception is thrown.
    But when i try to implement the same with jdbc the data in the database is not rolled back. When i debug, i can see the spring framework apis call the connection.rollback() but this has no impact on the database. Meaning to say, the transaction in the database is not rolled back.
    Here is the config file for the same;

    <aop:config proxy-target-class="true">
    <aopointcut id="hibernatePointCut"
    expression="execution(* util.txmanagement.dao.*.*(..))" />
    <aopointcut id="jdbcPointCut"
    expression="execution(* util.txmanagement.daojdbc.*.*(..))" />
    <aop:advisor advice-ref="txAdvice"
    pointcut-ref="hibernatePointCut" />
    <aop:advisor advice-ref="txAdviceJdbc"
    pointcut-ref="jdbcPointCut" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="check*" propagation="REQUIRED"
    rollback-for="BusinessException" isolation="READ_COMMITTED" />
    <tx:method name="get*" read-only="true" />
    <tx:method name="*" />
    </tx:attributes>
    </tx:advice>
    <tx:advice id="txAdviceJdbc" transaction-manager="txManagerJdbc">
    <tx:attributes>
    <tx:method name="check*" propagation="REQUIRED"
    rollback-for="BusinessException" isolation="READ_COMMITTED" />
    <tx:method name="*" />
    </tx:attributes>
    </tx:advice>
    <bean id="txManager"
    class="org.springframework.orm.hibernate3.Hibernat eTransactionManager">
    <property name="sessionFactory" ref="mysessionFactory" />
    </bean>
    <bean id="txManagerJdbc"
    class="org.springframework.jdbc.datasource.DataSou rceTransactionManager">
    <property name="dataSource" ref="dataSource" />
    </bean>
    <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverM anagerDataSource"
    destroy-method="close">
    <property name="driverClassName">
    <value>com.ibm.db2.jcc.DB2Driver</value>
    </property>
    <property name="url">
    <value>jdbc:db2://localhost:50001/testdb2</value>
    </property>
    <property name="username">
    <value>db2admin</value>
    </property>
    <property name="password">
    <value>Pass123$$</value>
    </property>
    </bean>

    Some help here would be great!!! Thanks in advance.

    Suryanarayan

  • #2
    Hi,

    do you use inside the jdbc based daos the jdbctemplate or native jdbc apis ?

    rgds
    agim

    Comment


    • #3
      You have 2 TransactionManagers, they interfere... Simply use 1, you only need the HibernateTransactionManager, you can remove the other.

      Please next time use [ code][/code ] tags when posting code.

      Code:
      <bean id="txManager" class="org.springframework.orm.hibernate3.Hibernat eTransactionManager">
        <property name="sessionFactory" ref="mysessionFactory" />
        <property name="dataSource" ref="datasource" />
      </bean>
      Code:
      <aop:config proxy-target-class="true">
      	<aop:pointcut id="daoMethod" expression="execution(* util.txmanagement.dao*..*(..))" />
      	<aop:advisor advice-ref="txAdvice" pointcut-ref="daoMethod" />
      </aop:config>
      
      <tx:advice id="txAdvice" transaction-manager="txManager">
      	<tx:attributes>
      		<tx:method name="check*" propagation="REQUIRED" rollback-for="BusinessException" isolation="READ_COMMITTED" />
      		<tx:method name="get*" read-only="true" />
      		<tx:method name="*" />
      	</tx:attributes>
      </tx:advice>
      The code above should be enough.
      Last edited by Marten Deinum; Sep 11th, 2007, 02:53 PM.

      Comment


      • #4
        Problems with Spring JDBC Transaction Management

        Thanks for the replies. The jdbc layer i have, uses the spring provided classes SqlUpdate, MappingSqlQuery for accessing the database. I tried removing the "DataSourceTransactionManager" but i still get the same rollback problem. According to the spring documentation for jdbc, one should use DataSourceTransactionManager for jdbc operations' tx management.
        I have tried using the TransactionProxyFactoryBean which is not recommended in the spring version 2.0 but still get the same rollback problem.

        Comment


        • #5
          According to the spring documentation for jdbc, one should use DataSourceTransactionManager for jdbc operations' tx management.
          You should use only 1 TransactionManager (that is also somewhere in the documentation). The HibernateTransactionManager is also very capable of managing normal JDBC transactions.

          Also only the removal of the DatasourceTransactionManager isn't enough, you also would need to change aop/tx config as I did. Can you post the new configuration, and the complete stacktrace? Next to that can we see the code which is executing the jdbc code and the code which is calling this.

          Comment


          • #6
            Hi mdeinum,
            Sorry for not replying earlier. For some urgent work, i was out of station for last couple of days. Coming back the message posted earlier, I had tried what you had suggested in your previous mail. But even that didnt work. There are no errors/exceptions so cant give you any stacktrace. I have seen the connection.rollback being called internally by the spring apis but as mentioned earlier this has no effect on the DB.

            Code:
            <?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:aop="http://www.springframework.org/schema/aop"
            	xmlns:tx="http://www.springframework.org/schema/tx"
            	xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
            
            	<!-- this bean will be transactional... -->
            	<bean id="personDAO"
            		class="ca.ab.wcb.arch.util.txmanagement.dao.PersonDAOImpl">
            		<property name="sessionFactory">
            			<ref bean="mysessionFactory" />
            		</property>
            	</bean>
            
            	<bean id="springJdbcDAO"
            		class="ca.ab.wcb.arch.util.txmanagement.daojdbc.SpringJdbcDAO" />
            
            
            	<aop:config proxy-target-class="true">
            
            		<aop:pointcut id="PointCut"
            			expression="execution(* ca.ab.wcb.arch.util.txmanagement.dao.*.*(..))" />
            
            
            		<aop:advisor advice-ref="txAdvice" pointcut-ref="PointCut" />
            
            
            	</aop:config>
            
            	<tx:advice id="txAdvice" transaction-manager="txManager">
            		<tx:attributes>
            			<tx:method name="check*" propagation="REQUIRED"
            				rollback-for="BusinessException" isolation="READ_COMMITTED" />
            			<tx:method name="get*" read-only="true" />
            			<tx:method name="*" />
            		</tx:attributes>
            	</tx:advice>
            
            	<bean id="txManager"
            		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            		<property name="sessionFactory" ref="mysessionFactory" />
            	</bean>
            
            	<bean id="dataSource"
            		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
            		destroy-method="close">
            		<property name="driverClassName">
            			<value>com.ibm.db2.jcc.DB2Driver</value>
            		</property>
            		<property name="url">
            			<value>jdbc:db2://localhost:50001/testdb2</value>
            		</property>
            		<property name="username">
            			<value>db2admin</value>
            		</property>
            		<property name="password">
            			<value>Pass123$$</value>
            		</property>
            	</bean>
            
            
            	<bean id="mysessionFactory"
            		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            		<property name="dataSource">
            			<ref bean="dataSource" />
            		</property>
            		<property name="configLocation">
            			<value>hibernate.cfg.xml</value>
            		</property>
            		<property name="configurationClass">
            			<value>org.hibernate.cfg.AnnotationConfiguration</value>
            		</property>
            		<property name="hibernateProperties">
            			<props>
            				<prop key="hibernate.dialect">
            					org.hibernate.dialect.DB2Dialect
            				</prop>
            				<prop key="hibernate.hbm2ddl.auto">update</prop>
            				<prop key="hibernate.connection.release_mode">
            					on_close
            				</prop>
            			</props>
            		</property>
            	</bean>
            
            	<bean id="txpersonService"
            		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            		<property name="proxyInterfaces">
            			<list>
            				<value>
            					ca.ab.wcb.arch.util.txmanagement.daojdbc.ISpringJdbcDAO
            				</value>
            			</list>
            		</property>
            		<property name="target">
            			<ref bean="springJdbcDAO" />
            		</property>
            		<property name="transactionManager">
            			<ref bean="txManager" />
            		</property>
            		<property name="transactionAttributes">
            			<props>
            				<prop key="checkInValidJdbcTransaction">
            					PROPAGATION_REQUIRED
            				</prop>
            			</props>
            		</property>
            	</bean>
            
            </beans>
            regards
            Suryanarayan

            Comment


            • #7
              I was using other id for login

              Hi,
              Sorry about this, I was earlier using anuragkhanna's id for posting as my id was not working on the forum thanks.
              Suryanarayan

              Comment


              • #8
                Some help in JTA

                Hi, I needed some help in implementing transaction mgmt for XA transactions with spring. I tried JBossTS for standalone tx mgmt. The problem i faced was, the transactions were not rolled back even after throwing a RuntimeException. Could any one give me some detailed information on how i can build a tx mgmt independent of applictaion server with spring apis.
                Thanks

                Comment


                • #9
                  If you need XA transaction you will need the JTATransactionManager and not the HibernateTransaction manager. Also when using that ALL of your DataSources have to be XA capable/aware.

                  Your configuration is still weird/wrong you are using both a TransactionProxyFactoryBean AND and a AOP/TX part. Remove the TransactionProxyFactoryBean and rewrite your pointcut (as what I advices earlier)

                  Code:
                  <aop:config proxy-target-class="true">
                  	<aop:pointcut id="daoMethod" expression="execution(* ca.ab.wcb.arch.util.txmanagement.dao*..*(..))" />
                  	<aop:advisor advice-ref="txAdvice" pointcut-ref="daoMethod" />
                  </aop:config>
                  Also WHERE and HOW are you using the JdbcDao I don't see it being injected anywhere? Do you retrieve it somewhere?

                  Comment


                  • #10
                    Deinum,
                    Sorry about posting incorrect config earlier, here is the correct config
                    Code:
                    <?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:aop="http://www.springframework.org/schema/aop"
                    	xmlns:tx="http://www.springframework.org/schema/tx"
                    	xmlns:jee="http://www.springframework.org/schema/jee"
                    	xsi:schemaLocation="
                        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
                        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
                        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
                    
                    
                    	<!-- this bean will be transactional... -->
                    	<bean id="personDAO"
                    		class="util.txmanagement.dao.PersonDAOImpl">
                    		<property name="sessionFactory">
                    			<ref bean="mysessionFactory" />
                    		</property>
                    	</bean>
                    
                    	<bean id="springJdbcDAO"
                    		class="util.txmanagement.daojdbc.SpringJdbcDAO" />
                    
                    
                    	<aop:config proxy-target-class="true">
                    
                    		<aop:pointcut id="daoMethod"
                    			expression="execution(* util.txmanagement.dao.*.*(..))" />
                    
                    
                    		<aop:advisor advice-ref="txAdvice"
                    			pointcut-ref="daoMethod" />
                    
                    	</aop:config>
                    
                    	<tx:advice id="txAdvice" transaction-manager="txManager">
                    		<tx:attributes>
                    			<tx:method name="check*" propagation="REQUIRED"
                    				isolation="DEFAULT" />
                    			<tx:method name="get*" read-only="true" rollback-for="BusinessException" />
                    			<tx:method name="*" />
                    		</tx:attributes>
                    	</tx:advice>
                    
                    	<bean id="txManager"
                    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                    		<property name="sessionFactory" ref="mysessionFactory" />
                    	</bean>
                    
                    	<bean id="dataSource"
                    		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
                    		destroy-method="close">
                    		<property name="driverClassName">
                    			<value>com.ibm.db2.jcc.DB2Driver</value>
                    		</property>
                    		<property name="url">
                    			<value>jdbc:db2://localhost:50001/testdb2</value>
                    		</property>
                    		<property name="username">
                    			<value>db2admin</value>
                    		</property>
                    		<property name="password">
                    			<value>Pass123$$</value>
                    		</property>
                    	</bean>
                    
                    
                    	<bean id="mysessionFactory"
                    		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                    		<property name="dataSource">
                    			<ref bean="dataSource" />
                    		</property>
                    		<property name="configLocation">
                    			<value>hibernate.cfg.xml</value>
                    		</property>
                    		<property name="configurationClass">
                    			<value>org.hibernate.cfg.AnnotationConfiguration</value>
                    		</property>
                    		<property name="hibernateProperties">
                    			<props>
                    				<prop key="hibernate.dialect">
                    					org.hibernate.dialect.DB2Dialect
                    				</prop>
                    				<prop key="hibernate.hbm2ddl.auto">update</prop>
                    				<prop key="hibernate.connection.release_mode">
                    					on_close
                    				</prop>
                    			</props>
                    		</property>
                    	</bean>
                    
                    
                    </beans>
                    This is the result and some observations;
                    1. Still the Jdbc transactions are not rolled back.
                    2. The springJdbcDAO bean accesses the RDBMS through the Jdbc layer.
                    3. I know for XA transactions the Transaction Manager has to be XA compliant. And that is why I used JTA compliant tx managers like the JBossTS and JOTM. But in both these cases the transactions are not rolled back even the hibernate transactions are not rollled back. With HibernateTransactionManager at least the hibernate transactions were getting rolled back.
                    4. "Spring In Action" book states if nothing works then JTA should work to your application needs. In my case this is not true.
                    5. Please ignore the difference in package structure as compared to the earlier example.
                    Last edited by Surya1234; Sep 17th, 2007, 09:55 AM. Reason: typo

                    Comment


                    • #11
                      How are you accessing your SpringJDBCDaoBean? Does it get injected? Do you create a new instance? Can you post the calling code?

                      Comment


                      • #12
                        For XA you need JTA, XA capable datasource, XA capable driver and XA capable database.

                        You are using HibernateTransactionManager with DriverManagerDataSource and that can't work. HibernateTransactionManager has nothing to do with JTA, you need org.springframework.transaction.jta.JtaTransaction Manager instead. XA DataSource you usually get by JNDI lookup of the server-side datasource.

                        If you need only one database why do you need JTA?

                        Comment


                        • #13
                          Spring Transaction Management

                          I am using the spring to generate the SpringJDBC dao object using IOC. The code for that is
                          Code:
                          factory = new ClassPathXmlApplicationContext(
                          				"transaction-management.xml");
                          		personDAO = (PersonDAO) factory.getBean("personDAO");
                          		springJdbcDAO = (ISpringJdbcDAO) factory.getBean("springJdbcDAO");
                          I am trying the XA transactions not for the same database but two different databases. I am not using HibernateTransaction Manager for that.
                          What i meant earlier was, the open source JTA implementations like JBossTS dont seem to rollback transactions. They would not even rollback transactions of hibernate on a single database/datasource.
                          I am now trying with Websphere Application Server support for JTA using jndi.

                          Comment


                          • #14
                            The above code snippet explains WHY everything is happening. It is happening the way you configured it. Each call to a dao is in a SEPARATE transaction. You need to execute it in 1 transaction. The configuration above wouldn't even work with a JTA Transactionmanager as you already noticed.

                            What is happening! (assuming the code below)

                            Code:
                            factory = new ClassPathXmlApplicationContext("transaction-management.xml");
                            personDAO = (PersonDAO) factory.getBean("personDAO");
                            springJdbcDAO = (ISpringJdbcDAO) factory.getBean("springJdbcDAO");
                            
                            personDAO.someMethod();
                            springJdbcDAO.someJdbcMethod();
                            Before executing the someMethod a transaction is started, when that is finished the transaction is committed. When someJdbcMethod is executed a transaction is started when finished the transaction will be committed.


                            Schematically
                            Code:
                            <start transaction>
                            personDAO.someMethod();
                            <commit transaction>
                            <start transaction>
                            springJdbcDAO.someJdbcMethod();
                            <commit transaction>
                            This behavior doesn't change regardless of which TransactionManager (or TransactionManagers) you use. It is in your way of coding which is wrong.

                            Create a Service which wrappes those to calls and make the Service transactional and for that use the JTATransactionManger (because you have different XA DataSources).

                            Code

                            Code:
                            public interface SomeService {
                               void processPerson();
                            }
                            
                            public class SomeServiceImpl implements SomeService {
                            
                              private PersonDAO personDAO;
                              private SpringJdbcDAO springJdbcDAO;
                            
                              public void processPerson() {
                                personDAO.someMethod();
                                springJdbcDAO.someJdbcMethod();
                              }  
                            
                            
                              public void setPersonDAO(PersonDAO personDAO) {
                                this.personDAO=personDAO;
                              }
                            
                              public void setSpringJdbcDAO(SpringJdbcDAO springJdbcDAO) {
                                this.springJdbcDAO=springJdbcDAO;
                              }
                            
                            
                            }
                            Transactions should be on your service

                            Code:
                            <?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:aop="http://www.springframework.org/schema/aop"
                            	xmlns:tx="http://www.springframework.org/schema/tx"
                            	xmlns:jee="http://www.springframework.org/schema/jee"
                            	xsi:schemaLocation="
                                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
                                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
                                http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
                            
                            
                            	<bean id="personDAO" class="util.txmanagement.dao.PersonDAOImpl">
                            		<property name="sessionFactory" ref="mysessionFactory"/>
                            	</bean>
                            
                            	<bean id="springJdbcDAO" class="util.txmanagement.daojdbc.SpringJdbcDAO" />
                            
                                <bean id="someService" class="util.txmanagement.service.SomeServiceImpl">
                                  <property name="personDAO" ref="personDAO"/>
                                  <property name="springJdbcDAO" ref="springJdbcDAO"/>
                                </bean>
                            
                            	<aop:config>
                            		<aop:pointcut id="serviceMethod" expression="execution(* util.txmanagement..*ServiceImpl.*(..))" />
                            		<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
                            	</aop:config>
                            
                            	<tx:advice id="txAdvice" transaction-manager="txManager">
                            		<tx:attributes>
                            			<tx:method name="check*" propagation="REQUIRED"
                            				isolation="DEFAULT" />
                            			<tx:method name="get*" read-only="true" rollback-for="BusinessException" />
                            			<tx:method name="*" />
                            		</tx:attributes>
                            	</tx:advice>
                            
                            	<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                            		<property name="sessionFactory" ref="mysessionFactory" />
                            	</bean>
                            
                            	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
                            		<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"/>
                            		<property name="url" value="jdbc:db2://localhost:50001/testdb2"/>
                            		<property name="username" value="db2admin"/>
                            		<property name="password" value="Pass123$$"/>
                            	</bean>
                            
                            	<bean id="mysessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                            		<property name="dataSource" ref="dataSource"/>
                            		<property name="configLocation" value="hibernate.cfg.xml"/>
                            		<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>
                            		<property name="hibernateProperties">
                            			<props>
                            				<prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
                            				<prop key="hibernate.hbm2ddl.auto">update</prop>
                            				<prop key="hibernate.connection.release_mode">on_close</prop>
                            			</props>
                            		</property>
                            	</bean>
                            
                            </beans>
                            The configuration above works with the HibernateTransactionManager but if you need transactions spanning multiple DataSources you need a JTATransactionManager.

                            I strongly suggest you read up on transactions and TransactionManagement in Spring, also try to understand the proxing mechanism in Spring and what is executed/added when.
                            Last edited by Marten Deinum; Sep 18th, 2007, 01:49 AM. Reason: Added configuration

                            Comment


                            • #15
                              Originally posted by mdeinum View Post
                              The above code snippet explains WHY everything is happening. It is happening the way you configured it. Each call to a dao is in a SEPARATE transaction. You need to execute it in 1 transaction. The configuration above wouldn't even work with a JTA Transactionmanager as you already noticed.
                              .
                              Mdeinum,
                              May be i didnt explain the problem correctly. The client code you saw was a snippet from my junit test case. Which was designed to test both hibernate and jdbc transactions individually. And it does that obviously in different methods. And the transactions i am refering to are either pure jdbc or pure hibernate transactions. Meaning to say, when i say transaction was not rolled back i mean a call to a jdbc dao which executes jdbc DML commands in one method and throws an exception at the end of method. As shown below
                              Code:
                              public void checkInValidJdbcTransaction() {
                              	factory = new ClassPathXmlApplicationContext("testSpringJdbc.xml");
                              
                              
                              	// ----------- INSERT operation
                              
                              	// getting the insert worker object, and also preparing the object to be
                              	// inserted
                              	insertObjectTest = (InsertObject) factory.getBean("insertObjectTEST");
                              	setValueList.add(ID);
                              	setValueList.add(NAME);
                              	// inserting the object
                              	insertObjectTest.addObject(setValueList);
                              
                              	// ----------- END OF INSERT--------------
                              
                              	
                              	// ----------- UPDATE operation
                              
                              	// preparing for updation
                              	updateObjectTest = (UpdateObject) factory.getBean("updateObjectTEST");
                              	setValueList = new ArrayList<String>();
                              	conditionList = new ArrayList<String>();
                              	setValueList.add(UPDATEDNAME);
                              	conditionList.add(ID);
                              	updateObjectTest.updateObject(setValueList, conditionList);
                              	throw new BusinessException();
                              
                              }
                              Logically speaking the above mentioned inserts and updates should be rolled back once the exception is thrown.
                              Please note, even if i remove the hibernate section from my application I am still not able to rollback the jdbc transactions. I am in no way combining the hibernate transactions with jdbc transactions or vice versa in one single transaction.

                              Comment

                              Working...
                              X