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.

Другие вопросы по тегам