2013-05-30 3 views
3

Я пишу многопоточную программу в serviceImpl, используя Callable interface.I использую менеджер весны транзакций. Когда операция обновления выполняется в БД, она выполнена успешно. Но обновленные данные не отражаются в БД. Но когда я запускаю программу без многопоточности, она обновляется в DB.Весенний менеджер транзакций и многопоточность

Это моя конфигурация

<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> 

я могу перейти к другому подходу к операции manager.Just я хочу, чтобы подтвердить, если этот подход поддерживает или нет многопоточности. Итак, мой вопрос: Помогает ли менеджер транзакций Spring поддерживать многопоточность (я имею в виду только объявление аннотации или XML) Почему обновленные данные не отражены в БД в моем случае? Что может быть лучшим альтернативным подходом?

ответ

17

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

+0

Возможно ли передать активную транзакцию во второй поток? –

+0

Я сомневаюсь. Как может транзакционный аспект узнать, завершился ли второй поток транзакцией или нет? Кто будет совершать транзакцию в конце, если метод вернется до того, как порожденный поток (или вызываемый) завершил свою работу? –

+0

Если бы я сделал что-то подобное, я отвечал за правильную синхронизацию потоков. Может быть полезно, например, начать работу в потоке A и завершить ее в потоке B (следовательно, передать транзакцию между потоками). –

3

вы еще в том, как вы делаете многопоточность, поэтому я могу только догадываться, что вы сделали:

В YourService.doSomething(), он createThreads. Для каждого потока он выполняет действия, связанные с БД. Это правильно?

Как описано в другом ответе, контекст транзакции хранится в локальном потоке. Поэтому ваша логика в потоке не связана ни с какой транзакцией. Одна вещь, которую вы можете проверить, это, помимо логики в потоках, в doSomething() вы также выполняете некоторые действия DB. Вы обнаружите, что действия db, выполненные вами в doSomething(), совершаются, в то время как действия в потоках теряются.

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

Если вы хотите, чтобы все они были в одной транзакции, другой способ - вместо того, чтобы отдельный поток выполнял действие БД, потоки теперь выполняют тяжелую работу и возвращают результат в исходный поток (по очереди производителя-потребителя для пример). Созданный поток отвечает за сбор результатов и выполнение действий БД.

Лично я бы постарался не вручную передавать контекст транзакции вокруг другой темы. Это просто разрушает всю идею декларативной транзакции.

0

Возможно, вы захотите реализовать свой собственный TransactionSynchronizationManager весной и ввести его. Используйте что-то вроде InmheritableThreadLocal вместо ThreadLocal.

Смежные вопросы