使用Spring JDBC进行简单事务处理?

10
我正在开发一个使用Spring IoC和JDBC Template类的Java应用程序。我有一个DAO类,其中包含4个方法:m1()到m4()。m1在表t1上执行多个插入和更新操作,m2在表t2上执行,m3在t3上执行等等。
DAO方法的使用如下:
while(true)
{
  //process & generate data

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

  //sleep
}

我希望在4个连续的方法调用下,数据库操作是原子性的,即要么所有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

}

还有更好的方法吗?

4个回答

15

是的,Spring允许您以编程方式控制事务

个人而言,我更喜欢使用注释的声明式事务,具体如下:

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已经完成的所有操作都会被回滚。 - Chadwick
在这种情况下,你不需要。但是如果他们正在进行更新,你应该将它们注释为需要事务,否则如果你在doWork()上下文之外调用它们,你可能会发现自己在进行非事务性更新。 - cletus
当将@Transactional注释应用于私有方法时,它是否起作用? - Andrew Swan
2
是的,private(私有)不再像以前那样私有了。 :) - cletus

8

为了完整起见,编程解决方案如下:

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

1

Spring可以通过使用@ Transactional来处理所有这些问题,如上所述或者在XML中,如果您愿意的话。

正确理解所需的事务传播类型非常重要,这完全取决于您的应用程序。

默认情况下,如果不存在事务,则会启动事务,并且如果已经启动了事务,则会重用现有事务。 如果您希望所有4个DAO都是原子性的,则需要此行为。

将@Transactional放在管理调用DAO方法(MyService)的类上 - 此层以下的任何内容现在都将参与该事务边界。

i.e:

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

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

在代码中做这件事是完全不必要的。

请参阅此处以获取更多信息


1

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接