Spring менеджер транзакций и многопоточность
Я пишу многопоточную программу в serviceImpl с использованием интерфейса Callable. Я использую весенний менеджер транзакций. Когда операция обновления выполняется в БД, она выполняется успешно. Но обновленные данные не отражаются в БД.Но когда я запускаю программу без многопоточности, она обновляется в БД.
Это моя конфигурация
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" />
<tx:method name="find*" propagation="NOT_SUPPORTED" />
<tx:method name="get*" propagation="NOT_SUPPORTED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation" expression="execution(* *..*ServiceImpl.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
Я могу перейти к другому подходу для менеджера транзакций. Просто я хочу получить подтверждение, поддерживает ли этот подход многопоточность. Итак, мой вопрос: поддерживает ли менеджер транзакций Spring многопоточность (я имею в виду просто объявление аннотации или XML). Почему в моем случае обновленные данные не отражаются в БД? Какой может быть лучший альтернативный подход?
3 ответа
Транзакционный контекст, используемый Spring, хранится в локальной переменной потока. Таким образом, если вы запускаете новый поток или выполняете код в другом потоке, используя вызываемый модуль, этот код не будет частью транзакции, запущенной транзакционным аспектом Spring. Вот почему ваши данные не отображаются в базе данных.
Вы покажете, как вы делаете многопоточность, поэтому я могу только догадываться, что вы сделали:
В YourService.doSomething() он создает потоки. Для каждого потока он выполняет действия, связанные с БД. Это правильно?
Как описано в другом ответе, контекст транзакции хранится в локальном порядке потока. Следовательно, ваша логика в потоке не связана с какой-либо транзакцией. В этом можно убедиться, кроме логики потоков, в doSomething () вы также выполняете некоторые действия с БД. Вы обнаружите, что действия db, которые вы выполняли в doSomething (), совершаются, а действия в потоках теряются.
Один из разумных способов решения проблемы - обычно у нас есть уровень службы приложений, который служит единицей работы, и, следовательно, у нас есть граница транзакции (аналогично вашей службе). Ваш поток должен вызывать операции, предоставляемые сервисом. Конечно, они будут все в разных сделках.
Если вы хотите, чтобы все они были в одной транзакции, другой способ состоит в том, чтобы вместо того, чтобы отдельный поток выполнял действие БД, потоки теперь выполняют тяжелую работу и отправляют результат обратно в созданный поток (например, по очереди "производитель-потребитель"). Созданный поток отвечает за сбор результата и выполнение действий с БД.
Лично я бы постарался избежать передачи контекста транзакции вручную по другому потоку. Это просто разрушает саму идею декларативной сделки.
Возможно, вы захотите реализовать свой собственный TransactionSynchronizationManager в Spring и внедрить его. Используйте что-то вроде InmheritableThreadLocal вместо ThreadLocal.