Spring Transaction propagation REQUIRED, REQUIRES_NEW

断了今生、忘了曾经 提交于 2019-12-01 08:42:03

问题


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>

回答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)




回答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 :).




回答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.



来源:https://stackoverflow.com/questions/15795985/spring-transaction-propagation-required-requires-new

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!