Java – spring cannot propagate transactions to the recursive action of forkjoin
I am trying to implement a multithreading solution so that I can parallelize my business logic, including reading and writing to the database
Technology stack: Spring 4.0 2,Hibernate 4.3. eight
Here are some codes to discuss:
configuration
@Configuration public class PartitionersConfig { @Bean public ForkJoinPoolfactorybean forkJoinPoolfactorybean() { final ForkJoinPoolfactorybean poolFactory = new ForkJoinPoolfactorybean(); return poolFactory; } }
service
@Service @Transactional public class MyService { @Autowired private OtherService otherService; @Autowired private ForkJoinPool forkJoinPool; @Autowired private MyDao myDao; public void performPartitionedActionOnIds() { final ArrayList<UUID> ids = otherService.getIds(); MyIdPartitioner task = new MyIdsPartitioner(ids,myDao,ids.size() - 1); forkJoinPool.invoke(task); } }
Repository / Dao
@Repository @Transactional(propagation = Propagation.MANDATORY) public class IdsDao { public MyData getData(List<UUID> list) { // ... } }
RecursiveAction
public class MyIdsPartitioner extends RecursiveAction { private static final long serialVersionUID = 1L; private static final int THRESHOLD = 100; private ArrayList<UUID> ids; private int fromIndex; private int toIndex; private MyDao myDao; public MyIdsPartitioner(ArrayList<UUID> ids,MyDao myDao,int fromIndex,int toIndex) { this.ids = ids; this.fromIndex = fromIndex; this.toIndex = toIndex; this.myDao = myDao; } @Override protected void compute() { if (computationSetIsSamllEnough()) { computeDirectly(); } else { int leftToIndex = fromIndex + (toIndex - fromIndex) / 2; MyIdsPartitioner leftPartitioner = new MyIdsPartitioner(ids,fromIndex,leftToIndex); MyIdsPartitioner rightPartitioner = new MyIdsPartitioner(ids,leftToIndex + 1,toIndex); invokeAll(leftPartitioner,rightPartitioner); } } private boolean computationSetIsSamllEnough() { return (toIndex - fromIndex) < THRESHOLD; } private void computeDirectly() { final List<UUID> subList = ids.subList(fromIndex,toIndex); final MyData myData = myDao.getData(sublist); modifyTheData(myData); } private void modifyTheData(MyData myData) { // ... // write to DB } }
After doing this, I get:
I understand that this is perfectly normal because transactions do not propagate through different threads Therefore, one solution is to manually create a transaction in each thread as proposed in another similar question But it's not satisfactory for me, so I've been searching
I found a discussion on the topic in the spring forum I found a very interesting paragraph:
Therefore, the first question arises: is it worth simplifying the read / write of the database, and will it really damage the consistency of the database? If the above reference is incorrect, I doubt whether there is a way to achieve the following purposes: myidpartitioner will be managed by spring - using @ scope ("prototype") - and passing the required parameters for recursive calls, so that transaction management can be left to spring?
Solution
It should be possible to use atomikos( http://www.atomikos.com )You can also choose to use nested transactions
If you do so, if multiple threads of the same root transaction write to the same table in the database, please pay attention to avoid deadlock