Spring transaction manager and multithreading

2020-01-29 17:36发布

I am writing multithreading program in serviceImpl using Callable interface.I am using spring transaction manager.When update operation is executed in DB ,it is executed successfully .But the updated data is not reflected in DB.But When i run program without multithreading it is updated in DB.

This is my configuration

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

I can shift to another approach for transaction manager.Just i want to get confirm if this approach supports or not for multithreading. So my question is Do spring transaction manager supports multithreading(I mean just by declaring annotation Or XML ) Why updated data is not reflected in DB in my case? What can be the best alternative approach ?

3条回答
甜甜的少女心
2楼-- · 2020-01-29 18:01

The transactional context used by Spring is stored in a thread-local variable. So if you start a new thread, or execute code in another thread using a callable, this code won't be part of the transaction started by the Spring transactional aspect. That's why your data doesn't appear in the database.

查看更多
你好瞎i
3楼-- · 2020-01-29 18:02

You haven's show how you are doing multi-threading, so I can only guess what you have done:

In YourService.doSomething(), it createThreads. For each thread, it is doing DB related actions. Is that right?

As desecribed in another answer, transaction context is stored in thread local manner. Therefore, your logic in thread has no association with any transaction. One thing you can verify this is, apart from the logics in threads, in doSomething() you also do some DB actions. You will find that db actions you performed in doSomething() is committed while actions in threads are lost.

One of the reasonable way to solve is, normally we have a layer of application service which serves as a unit-of-work, and hence, we have transaction boundary on it (similar to your Service). Your thread should invoke the operations provided by the service. Of course, they will be all in different transaction.

If you want them all in one transaction, another way is, instead of let individual thread do the DB action, threads now do the heavy work and post the result back to the originated thread (by a producer-consumer queue for example). The originated thread is responsible to gather the result and perform DB actions.

Personally I would try to avoid manually passing the transaction context around different thread. This is simply ruining the whole idea of declarative transaction.

查看更多
▲ chillily
4楼-- · 2020-01-29 18:17

You might want to implement your own TransactionSynchronizationManager in Spring and inject it. Use something like InmheritableThreadLocal instead of ThreadLocal.

查看更多
登录 后发表回答