【问题标题】:How to get transactionManager reference in Spring Programmatic transaction如何在 Spring Programmatic 事务中获取 transactionManager 参考
【发布时间】:2012-02-20 11:45:23
【问题描述】:

我想在从队列接收消息的 JMS 应用程序中使用 spring 编程事务。同时,我想将队列包含在事务范围内。

使用 Spring DefaultMessageListnereContainer 并在其中注入事务管理器。但是,不确定如何获取此事务的引用以以编程方式提交或回滚?


我在这里阅读并理解“在事务中处理消息” http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/jms.html#jms-tx-participation

我的 2 个要求是 - 1) XA 事务因此注入 JtaTransactionManager, 2) 使用编程事务 - 这里我需要帮助如何在代码中获取对 spring 启动的事务的引用,以便我可以以编程方式处理事务

【问题讨论】:

    标签: spring transactions jms


    【解决方案1】:

    Spring 使用 PlatformTransactionManager 抽象底层事务管理器。
    在运行时,我们可以注入平台特定的事务管理器,如下图所示。

    我们可以通过以下两种方式在spring编程方法中获取Transaction Manager引用:

    1. 使用接口 PlatformTransactionManager :我们必须显式创建TransactionDefinitionTransactionStatus 对象。

    例如:

           @Resource
           private PlatformTransactionManager transactionManager;
           public void create(String name, Integer age, Integer marks, Integer year){
    
              TransactionDefinition def = new DefaultTransactionDefinition();
              TransactionStatus status = transactionManager.getTransaction(def);
    
          try {
                 //jmsTemplate statements
                 transactionManager.commit(status);
              } catch (DataAccessException e) {
                 System.out.println("Error in creating record, rolling back");
                 transactionManager.rollback(status);
                 throw e;
              }
    
    1. 使用类 TransactionTemplate :

    我们不必显式创建TransactionDefinitionTransactionStatus 对象。 TransactionTemplate 提供了一个名为 execute 的回调方法,我们可以在其中添加我们想要包装在事务中的业务逻辑。

    我们可以使用两种类型的回调方法来包装我们的代码,即TransactionCallbackWithoutResultTransactionCallback(T)

    例如:

    @Resource
    private TransactionTemplate transactionTemplate;
    
    public void deleteUser(final int uid) {
      transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        protected void doInTransactionWithoutResult(TransactionStatus paramTransactionStatus) {
        try{
            //statements
        }catch (Exception e) {
          //use this to rollback exception in case of exception
          paramTransactionStatus.setRollbackOnly();
        }
        }
      });
    
    }
    
    public int insertUser(final User user) {
    //use TransactionCallback handler if some result is returned
    return  transactionTemplate.execute(new TransactionCallback<Integer>() {
      public Integer doInTransaction(TransactionStatus paramTransactionStatus) {
        //statements
       }
     });
    }
    

    【讨论】:

    • 我使用第一种方法,我注意到一些异常会使连接处于不良状态。因此,使用池中该连接的以下请求会引发错误。除了回滚还有什么可做的吗?
    【解决方案2】:

    你首先必须注入org.springframework.transaction.PlatformTransactionManager - 它和其他所有的bean一样是一个普通的bean:

    @Resource
    private PlatformTransactionManager transactionManager;
    

    现在你可以和TransactionTemplate一起使用了:

    final TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
    transactionTemplate.execute(new TransactionCallback<String>() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
            transactionManager.rollback(status);
            return ":-(";
        }
    });
    

    相当多的代码,所以你应该这样做:

    @Transactional
    public void onMessage(Message message) {
        //rollback:
        throw new HoustonException("We've got a problem!");
    }
    

    如果您从@Transactional 方法中抛出RuntimeException,它将自动回滚该事务。否则它将被提交。

    请注意,这并不意味着 JMS 和数据库正在处理同一个事务!当您抛出异常时,JMS 代理将尝试重新传递消息,但是在提交数据库事务后代理可能会失败。如果您需要 100% 确定 JMS 和 DB 更新都是原子的,那么您需要分布式事务管理器。

    【讨论】:

    • 这会将消息放回队列中吗?即队列是否在事务范围内?
    • 可以不使用TransactionTemplate直接使用transactionManager吗?
    • @user1166503:这有点复杂(和理论上的) - 在默认配置中会发生以下情况:JMS tx start、DB tx start、DB tx commit、JMS tx commit。如果在第 3 步和第 4 步之间发生了什么,JMS tx 将回滚,但 DB 已提交。这是一个问题,因为数据是持久化的,但消息将被放回队列。 / 可以,可以直接使用PlatformTransactionManager,但是有点不方便,模板尽量简化。
    • 这有帮助,但仍然不确定您提供的事务回滚代码将如何添加到 onMessage() 方法中?该方法具有@Transactional 注释以及程序化事务。
    • @user1166503:第一个代码 sn -p 创建一个新的数据库事务并将其回滚。后者将回滚,因为异常转义onMessage(准确地说,您还必须添加自定义ErrorHandler,因为Spring 吞下JMS onMessage() 异常。
    猜你喜欢
    • 2012-07-31
    • 2011-10-05
    • 2020-05-27
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 2022-07-01
    • 1970-01-01
    相关资源
    最近更新 更多