Spring transaction manager and multithreading
Asked Answered
A

3

4

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 ?

Aoristic answered 30/5, 2013 at 12:19 Comment(0)
D
25

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.

Disassociate answered 30/5, 2013 at 12:24 Comment(3)
Is it possible to pass the active transaction to a second thread?Dough
I doubt it. How could the transactional aspect know if the second thread has finished with the transaction or not? Who would commit the transaction in the end if the method returns before the spawned thread (or callable) has finished its work?Disassociate
If I'd do something like that, I'm responsible for the proper synchronization of the threads. It might be useful, for example, to start work in thread A and finish it in thread B (hence passing the transaction between threads).Dough
T
4

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

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

As described 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.

Truncheon answered 31/5, 2013 at 3:26 Comment(0)
H
0

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

Haldeman answered 1/2, 2017 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.