Как распространить транзакцию Spring в другой поток? - PullRequest
4 голосов
/ 08 марта 2011

Возможно, я делаю что-то не так, но не могу найти хороший выход для следующей ситуации.

Я хотел бы провести модульное тестирование службы, использующей Spring Batch внизу, чтобы выполнить работу.Задания выполняются через предварительно настроенные AsyncTaskExecutor в отдельных потоках.В моем модульном тесте я хотел бы:

  1. Создать несколько объектов домена и сохранить их с помощью DAO
  2. Вызвать сервисный метод для запуска задания
  3. Подождите, показадание завершено
  4. Использование DAO для извлечения объектов домена и проверки их состояния

Очевидно, что все вышеперечисленное должно выполняться внутри одной транзакции, но, к сожалению, транзакции не распространяются нановые темы (я понимаю причину этого).

Идеи, которые пришли мне в голову:

  • Зафиксируйте транзакцию # 1 после шага (1).Это не хорошо, так как состояние БД следует откатывать после модульного теста.
  • Использовать Isolation.READ_UNCOMMITTED в конфигурации задания.Но это требует двух разных конфигураций для тестирования и производства.

Ответы [ 3 ]

3 голосов
/ 10 января 2012

Хотя это не верное решение вашего вопроса, я нашел возможным запустить новую транзакцию внутри рабочего потока вручную. В некоторых случаях этого может быть достаточно.

Источник: Весенние программные транзакции .

Пример:

@PersistenceContext
private EntityManager entityManager;
@Autowired
private PlatformTransactionManager txManager;

/* in a worker thread... */
public void run() {
    TransactionStatus tx = txManager.getTransaction(new DefaultTransactionDefinition());
    try {
        entityManager.find(...)
        ...
        entityManager.flush(...)
        etc...
        txManager.commit(tx);
    } catch (RuntimeException e) {
        txManager.rollback(tx);
    }
}
2 голосов
/ 24 апреля 2011

Я думаю, что самым простым решением было бы настроить JobLauncher с SyncTaskExecutor во время выполнения теста - таким образом, задание выполняется в том же потоке, что и тест, и разделяет транзакцию.

Конфигурация исполнителя задачи может быть перемещена в отдельный XML-файл конфигурации Spring. Имеется две его версии - одна с SyncTaskExecutor, которая используется во время тестирования, и другая AsyncTaskExecutor, которая используется для производственных прогонов.

1 голос
/ 08 марта 2011

Если вам нужны отдельные конфигурации, я бы порекомендовал создать шаблон политики изоляции в своей конфигурации и получить ее значение из файла свойств, чтобы не допустить различий в наборе конфигураций Spring для тестирования и производства.

Но я согласен, что использование той же политики выгодно для производственных целей. Насколько обширны данные вашего прибора и как плохо было бы иметь шаг setUp(), который сдул и перестроил ваши данные (возможно, из снимка, если данных много), чтобы вам не пришлось полагаться на откаты?

...