Question

I am working on a Java app that uses Spring IoC and JDBC Template classes. I have a DAO class that has 4 methods : m1() to m4(). m1 performs multiple inserts and updates on table t1, m2 on table t2, m3 on t3, etc.

The DAO methods are used as follows:

while(true)
{
  //process & generate data

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

  //sleep
}

I want the db operations under the 4 consecutive method calls to be atomic, either all the 4 tables are updated successfully or none are. So, if there is an error while performing operations in m3(), i want to rollback all the changes(updates & inserts) performed in m2 & m1.

So does spring let you do it the following way ?

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

}

or are there better ways to do it?

Was it helpful?

Solution

For completeness, the programmatic solution would be:

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

OTHER TIPS

Yes Spring allows you to programmatically control transactions.

Personally I prefer declarative transactions using annotations, which goes like this:

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

where the DAO functions are defined:

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

This requires in your applicationContext.xml:

<tx:annotation-driven/>

Declarative transactions can be declared to require a transaction, require a new transaction, support transactions, etc. Rollback will occur when a block annotated with @Transactional throws a RuntimeException.

Yes, you can put those calls inside a method and specify your transactions declaratively.

You don't need to add that code - Spring can do it for you.

Spring can handle this all for you by using @Transactional as explained or in XML if you'd prefer.

The import thing to get right is the type of Transaction Propagation you want which all depends on your application.

By default a transaction will be started if one doesn't exist, and will re-use an existing transaction if one has already been started. This is the behavior you want if you want all 4 DAOs to be atomic.

Put @Transactional on a class which will manage the DAO methods called (MyService) - anything below this layer will now take part in that transaction boundary.

i.e:

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

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

Doing this in code is completely unnecessary.

See here for more info

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top