Spring Transaction propagation REQUIRED, REQUIRES_NEW

19,433

Solution 1

I had the same problem earlier and it was solved here : Strange behaviour with @Transactional(propagation=Propagation.REQUIRES_NEW)

Using default setting, there won't be any new transaction proxy created when you call doService2() from the same class, as a result your annotation is not user.

To avoid this issue you can put doService2() in another class or use aspectJ for transaction by declaring it like this : <tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>

Best solution will depend on your application. (The second one here seems more appropriate)

Solution 2

The call to doService2() probably doesn't have any transaction advice running on it because I'm assuming you're using a JDK dynamic proxy (interface proxy) instead of CGLIB based proxies. If you don't already know about how this works you might want to read: http://static.springsource.org/spring/docs/3.0.x/reference/aop.html#aop-proxying .

If you're not using CGLIB (target-class proxying), it will never go through the Spring Transaction advisor when you call doService2() since it is invoking the method directly instead of going through the wrapper Spring creates for your service at startup time.

You can get your example working by moving doService2() to a different service class then injecting it on to this service. That way you'll be going through the proxy and the transaction advice will run.

Otherwise, if you're ready to make a bigger change to your project, you could get your example to work as-is: 1) make sure CGLIB is in your classpath, and 2) turn on proxy-target-class , or force it to use CGLIB proxying so by getting rid of your service interface.

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

If you're going to do this, make sure you're read through the first link :).

Solution 3

According to spring documentation(Check section 10.5.6.1),the spring framework transaction will Rollback for only RunTimeException.
Not for other checked excpetions like SqlException. So if you really want a rollback for this exception you have to specify it like below

@Transactional(propagation=Propagation.REQUIRES_NEW,rollbackFor=SQLException.class)
public void doService2(){
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    String sql = "  update aa set a_name = 'hhh' where a_id = 4 and " ;
    int rowCount1 =  jdbcTemplate.update(sql);
    System.out.println(" rowCount2 >" + rowCount1);
}

Try this and let me know if it works.
Also this might help more.

Share:
19,433
user2241925
Author by

user2241925

Updated on July 24, 2022

Comments

  • user2241925
    user2241925 almost 2 years

    in following code method doService1() update correct sql but doService2() sql has some issue , but when i call doService() it has to commit the doService1() update to DB even though the doService2() has a sql exception because doService2() has a REQUIRES_NEW Propagation type but when i nun this doService1() update does not commit DB..

    @Service public class DbClass {
    
          static Logger log = Logger.getLogger(
                  DbClass.class.getName());
    
    @Autowired
    private DataSource dataSource;
    
    @Transactional(propagation=Propagation.REQUIRED)
    public void doService(){
        doService1();
        doService2();
    }
    
    @Transactional(propagation=Propagation.REQUIRED)
    public void doService1(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "  update BATCHJOBSTATUS set PROCESSINGDATE = '20130322'  " ;
        int rowCount1 =  jdbcTemplate.update(sql);
        System.out.println(" rowCount1 >" + rowCount1);
    }
    
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void doService2(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "  update aa set a_name = 'hhh' where a_id = 4 and " ;
        int rowCount1 =  jdbcTemplate.update(sql);
        System.out.println(" rowCount2 >" + rowCount1);
    }   
    }
    

    as your guys suggestion test in following way as well but still facing the same problem. here i doService2() in a separate class but even though still have the same problem as above

    @Service
    public class DbClass {
    
      static Logger log = Logger.getLogger(
              DbClass.class.getName());
    
    @Autowired
    private DataSource dataSource;
    
    @Autowired
    private DbClass2 dbClass2;
    
    @Transactional
    public void doService(){
        doService1();
        dbClass2.doService2();
    }
    
    @Transactional(propagation=Propagation.REQUIRED )
    public void doService1(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "  update BATCHJOBSTATUS set PROCESSINGDATE = '20130322'  " ;
        int rowCount1 =  jdbcTemplate.update(sql);
        System.out.println(" rowCount1 >" + rowCount1);
    
        }
    
    
    }
    
    
    @Service
    public class DbClass2 {
    
    
    @Autowired
    private DataSource dataSource;
    
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void doService2() {
        System.out.println("*******doService2*********`");
    
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    
        String sql = "  update aa set a_name = 'hhh' where a_id_ = 4  " ;
    
        int rowCount2 =  jdbcTemplate.update(sql);
    
        System.out.println(" rowCount2 >" + rowCount2);
    
    }
    
    }
    
    
    
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:oxm="http://www.springframework.org/schema/oxm"
             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-3.0.xsd
                 http://www.springframework.org/schema/tx 
         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
         http://www.springframework.org/schema/aop 
         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
    
    
        <context:annotation-config />
    
        <context:component-scan base-package="com.spring"/>
    
          <tx:annotation-driven transaction-manager="txManager1" proxy-target-class="true"/>
    
    
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
            <property name="url" value="jdbc:oracle:thin:@192.168.8.121:1521:h3" />
            <property name="username" value="admin" />
            <property name="password" value="admin" />
        </bean>
    
    
      <bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
      <property name="dataSource" ref="dataSource"/>
      </bean>
    
        <bean id="batchJob" class="com.spring.jdbc.BatchJob">
        </bean>
    
    
    </beans>
    
  • user2241925
    user2241925 about 11 years
    Thanks for the reply.. when i use mode="aspectj" for above code committing happen for the doService1() this is fine, but i m having another issue not when i changer doService2() annotation as @Transactional(propagation=Propagation.MANDATORY) this is not roll back the doService1() work, please kindly advice me on this.
  • user2241925
    user2241925 about 11 years
    Thanks for the reply. i tried with your suggestion but no good result still have the same problem, I tied with the separate class as well but that also not working as i expected .
  • DessDess
    DessDess about 11 years
    You mean that when you're using annotation @Transactional(propagation=Propagation.MANDATORY) on doService2(), an Exception thrown in doService2() is not rolling back doService1() ?
  • user2241925
    user2241925 about 11 years
    yes you are correct even though the Exception in doService2() this will not rolling back doService1(),
  • DessDess
    DessDess about 11 years
    I though that you wanted to avoid doService1() roll back ? Remove mode="aspectJ" and you should normally get a doService1() roll back with the mandatory propagation
  • DessDess
    DessDess about 11 years
    However, if you want a doService1() roll back, the @Transactional over doService() is sufficient
  • user2241925
    user2241925 about 11 years
    yes you are correct if i have the @Transactional over doService() that is sufficient, to roll back doService1(),
  • DessDess
    DessDess about 11 years
    @user2241925 Is your problem now solved ? Or do you have other question ? If it's solved set your question as answered to avoid duplicate
  • user2241925
    user2241925 about 11 years
    yes you are correct if i have the @Transactional over doService() that is sufficient, to roll back doService1(), but my test is the understand how propagation REQUIRED, REQUIRES_NEW works in spring transaction environment.
  • user2241925
    user2241925 about 11 years
    that the reason i test my sample with propagation REQUIRED, REQUIRES_NEW and test its behavior. so when i have REQUIRES_NEW in doService2() it is not roll back the doService1() that the my issue first time after i added mode="aspectj" as your suggestion this problem was ok, but when i have MANDATORY in doService2() doService1() have to roll back but that not happen, please advice.
  • DessDess
    DessDess about 11 years
    MANDATORY is just a way to be sure that you have an existing transaction opened otherwise it throws an error. Using simple @Transactional annotation does it rollback ?
  • user2241925
    user2241925 about 11 years
    yest with the @Transactional roll pack working but, when i have mode="aspectj" for the MANDATORY y it is not rollback ?
  • DessDess
    DessDess about 11 years
    If with @Transactional and mode="aspectJ" doService1() is roll backing I have to admit that I don't know why it is not working with MANDATORY
  • jonc
    jonc about 11 years
    Ahhh yeah. Looks like my memory was a little off on it :). T.Des's solution was right :).
  • Shailesh Pratapwar
    Shailesh Pratapwar almost 10 years
    I think the jdbcTemplate will wrap the SQLException in it's DataAccessException. And hence, users will only get DAE.stackoverflow.com/a/8916655