【问题标题】:Easy transactions using Spring JDBC?使用 Spring JDBC 的简单事务?
【发布时间】:2009-06-21 13:35:42
【问题描述】:

我正在开发一个使用 Spring IoC 和 JDBC 模板类的 Java 应用程序。我有一个 DAO 类,它有 4 个方法:m1() 到 m4()。 m1 在表 t1 上执行多次插入和更新,在表 t2 上执行 m2,在 t3 上执行 m3 等。

DAO 方法使用如下:

while(true)
{
  //process & generate data

  dao.m1(data1);
  dao.m2(data2);
  dao.m3(data3);
  dao.m4(data4);

  //sleep
}

我希望 4 个连续方法调用下的 db 操作是原子的,要么所有 4 个表都成功更新,要么没有。因此,如果在 m3() 中执行操作时出现错误,我想回滚在 m2 和 m1 中执行的所有更改(更新和插入)。

那么 spring 是否允许您按照以下方式进行操作?

while (true)
{
  //process & generate data

  transaction = TransactionManager.createNewTransaction();

  transaction.start()

  try
  {
    dao.m1(data1);
    dao.m2(data2);
    dao.m3(data3);
    dao.m4(data4);
  }
  catch(DbUpdateException e)
  {
    transaction.rollBack();
  }

  transaction.end();

  // sleep

}

或者有更好的方法吗?

【问题讨论】:

    标签: java spring jdbc transactions rollback


    【解决方案1】:

    是的 Spring 允许您programmatically control transactions。

    我个人更喜欢 declarative transactions 使用注解,它是这样的:

    public void runBatchJob() {
      while (true) {
        // generate work
        doWork(unitOfWork);
      }
    }
    
    @Transactional
    private void doWork(UnitOfWork work) {
      dao.m1(data1);
      dao.m2(data2);
      dao.m3(data3);
      dao.m4(data4);
    }
    

    DAO 函数的定义位置:

    @Transactional
    public void m1(Data data) {
      ...
    }
    

    这需要您的 applicationContext.xml:

    <tx:annotation-driven/>
    

    声明性事务可以声明为需要一个事务、需要一个新事务、支持事务等。当带有@Transactional 注释的块抛出RuntimeException 时,将发生回滚。

    【讨论】:

    • 我认为您不需要将 m1、m2 等注释为 @Transactional。如果有任何抛出异常,doWork 已经完成的所有事情都将被回滚。
    • 你不需要在这种情况下,不。但是如果他们正在做更新,你应该将它们注释为需要事务,否则如果你在 doWork() 上下文之外调用它们,你可能会发现自己在做非事务性更新。
    • @Transactional 注解在应用于私有方法时是否有任何作用?
    • 是的,private 不像以前那么私密了。 :)
    【解决方案2】:

    为了完整起见,程序化解决方案是:

    private TransactionTemplate transactionTemplate;
    
    public setTransactionManager(PlatformTransactionManager transactionManager) {
      this.transactionTemplate = new TransactionTemplate(transactionManager);
    }
    
    ...
    
    while (true) {
    
      transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        protected void doInTransactionWithoutResult(TransactionStatus status) {
          try {
            dao.m1(data1);
            dao.m2(data2);
            dao.m3(data3);
            dao.m4(data4);
          } catch(DbUpdateException e) {
            status.setRollbackOnly();
          }
        }
      });
    }
    

    【讨论】:

      【解决方案3】:

      是的,您可以将这些调用放在一个方法中并指定您的事务declaratively。

      您不需要添加该代码 - Spring 可以为您完成。

      【讨论】:

        【解决方案4】:

        Spring 可以按照说明使用 @Transactional 为您处理这一切,如果您愿意,也可以在 XML 中处理。

        正确的导入是您想要的 Transaction Propagation 类型,这完全取决于您的应用程序。

        默认情况下,如果一个事务不存在,则会启动一个事务,如果一个事务已经启动,则会重新使用现有事务。如果您希望所有 4 个 DAO 都是原子的,这就是您想要的行为。

        将@Transactional 放在一个将管理称为(MyService)的DAO 方法的类上——该层之下的任何东西现在都将参与该事务边界。

        即:

        @Transactional
        public void m1(Data data) {
         ...
        }
        
        @Transactional
        public void m2(Data data) {
         ...
        }
        

        完全没有必要在代码中这样做。

        见here for more info

        【讨论】:

          猜你喜欢
          • 2010-10-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-22
          • 1970-01-01
          • 2013-05-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多