当前位置: 首页 > 知识库问答 >
问题:

需要Spring事务传播,REQUIRES_NEW

纪实
2023-03-14

在以下代码方法中,更新正确的sql,但sql有一些问题,但是,当我调用doService()时,它必须将更新提交到DB,即使doService 2()有sql异常,因为doService 2()有一个新的传播类型,但是当我取消这个更新时,不会提交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);
}   
}

正如你们的建议,以以下方式进行测试,但仍然面临相同的问题。这里idoService2()在一个单独的类中,但即使仍然存在与上述相同的问题

@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>

共有3个答案

汪阿苏
2023-03-14

根据Spring留档(检查部分10.5.6.1),Spring框架事务将仅对RunTimeException进行回滚。
不适用于SqlException等其他检查过的例外。因此,如果您真的想要回滚此异常,您必须像下面这样指定它

@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);
}

试试这个,让我知道它是否有效<这可能会有更多帮助。

闻人锦
2023-03-14
匿名用户

调用doService2()可能没有任何事务建议,因为我假设您使用的是JDK动态代理(接口代理),而不是基于CGLIB的代理。如果您还不知道这是如何工作的,您可能需要阅读:http://static.springsource.org/spring/docs/3.0.x/reference/aop.html#aop-代理。

如果您没有使用CGLIB(目标类代理),那么当您调用doService2()时,它将永远不会通过Spring事务顾问,因为它直接调用该方法,而不是通过Spring在启动时为您的服务创建的包装。

您可以通过将doService2()移动到另一个服务类,然后将其注入到该服务中来运行示例。这样,您将通过代理运行事务建议。

否则,如果您准备对项目进行更大的更改,您可以让您的示例按原样工作:1)确保CGLIB在您的类路径中,2)打开proxy-Target-class,或者通过摆脱您的服务接口强制它使用CGLIB代理。

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

如果要这样做,请确保已阅读第一个链接:)。

邹野
2023-03-14

我之前遇到过同样的问题,它在这里得到了解决:@Transactional的奇怪行为(传播=传播。REQUIRES_NEW)

使用默认设置,当您从同一个类调用doService2()时,不会创建任何新的事务代理,因此您的注释不是用户。

要避免此问题,您可以将doService2()放在另一个类中或通过如下声明将aspectJ用于事务:

最佳解决方案取决于您的应用程序。(这里的第二个似乎更合适)

 类似资料:
  • 在下面的文章中说, 在此处输入链接描述 需要传播–支持当前交易;如果不存在,请创建一个新的。 下面是一个产品代码,然后是两个表的产品详细信息。 我的问题是什么时候会发生这种行为?我的意思是,当前交易怎么会结束?是在保存还是更新之后? 如果我们使用PROPAGATION_REQUIRED假设当前事务在插入产品后结束。然后一个新的事务来了,但是如果插入产品数量时出现任何故障,它只会回滚数量而不是输入的

  • 我试图理解Spring事务概念。如下所示,我必须将数据插入两个不同的数据库(iSeries和DB2),但我们的iSeries版本不支持两阶段提交。要求是,只有当两个插入都成功时才应该提交事务,否则应该回滚。 如果我根据需要使用传播或REQUIRES\u NEW,我会得到错误“非法尝试使用现有的两阶段资源提交一阶段资源”。 但是如果我使用NOT_SUPPORTED或支持,它工作正常(即如果其中一个插

  • 对于每个客户机,我们自然需要发送关于事务的反馈(OK或Exception->rollback)。 我的问题是:如果我使用,是否意味着只使用一个事务,如果第100个客户机遇到问题,第1个客户机的事务也会回滚?

  • 所称的刀是: 我希望服务类中的方法在事务中运行,并在方法出现异常时回滚所有内容。但这不是在事务中运行的。 如果我将添加到DAO方法中,那么它看起来就像是在单独的事务中运行的。这是正确的吗?

  • 我在存储库类中有一个方法,标记为,该方面正在执行,如stacktrace中所示,但抛出的异常是“Transaction required exception” 电磁场: 交易: 我真的要疯了,任何帮助都会很好。 似乎,有一个事务,它被检查为完成,加入事务失败,所以它标记为仅回滚,因为它不能加入它。

  • 这是我的问题: 我正在Java EE/Spring/Hibernate应用程序上运行批处理。此批处理调用方法1。该方法调用方法2,该方法可以引发用户异常(扩展RuntimeException的类)。下面是它的样子: 在继续执行时捕获异常,但在事务关闭时,method1结束时抛出回滚异常。 这是堆栈跟踪: 当method2不抛出这个异常时,它工作得很好。 我尝试过的: 设置在 尝试并抓住 但这并没有