Простые транзакции с использованием Spring JDBC? - PullRequest
9 голосов
/ 21 июня 2009

Я работаю над приложением Java, которое использует классы Spring IoC и JDBC Template. У меня есть класс 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
}

Я хочу, чтобы операции db при 4 последовательных вызовах методов были атомарными, либо все 4 таблицы обновлены успешно, либо нет. Итак, если при выполнении операций в m3 () возникает ошибка, я хочу откатить все изменения (обновления и вставки), выполненные в m2 & m1.

Значит, весна позволяет вам сделать это следующим образом?

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 голосов
/ 21 июня 2009

Да, 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.

8 голосов
/ 21 июня 2009

Для полноты, программное решение будет:

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 голос
/ 22 июня 2009

Spring может обработать все это для вас, используя @Transactional, как описано, или в XML, если вы предпочитаете.

Правильный выбор импорта - это тип Распространение транзакции , которое вы хотите, и все зависит от вашего приложения.

По умолчанию транзакция будет запущена, если она не существует, и будет повторно использовать существующую транзакцию, если она уже была запущена. Это поведение, которое вы хотите, если хотите, чтобы все 4 DAO были атомарными.

Поместите @Transactional в класс, который будет управлять методами DAO, называемыми (MyService) - все, что находится ниже этого уровня, теперь будет участвовать в этой границе транзакции.

то есть: * * +1011

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

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

Делать это в коде совершенно не нужно.

См. здесь для получения дополнительной информации

1 голос
/ 21 июня 2009

Да, вы можете поместить эти вызовы в метод и указать свои транзакции декларативно .

Вам не нужно добавлять этот код - Spring может сделать это за вас.

...