AOP, Spring and Transactional Overview

Introduce a transactional multi-threaded Java application using spring, jdbc, and aop with n classes in m packages that participate in database transactions. Now suppose that there is a need to encompass an arbitrary set of classes in a single transaction. In addition, there is always one class T within the scope of the transaction that is invoked.

Let me give you an example for clarity: Given packages A, B, Z and classes A.Foo, B.Bar and ZT The following instances of the corresponding classes are called (possibly by different callers with different classes between them): A.Foo, B.Bar , A.Foo, ZT Transactions will be completed only after calling ZT. If the application is closed for any reason, the transaction will never be completed if ZT is not involved.

Instances can call each other, and, as already mentioned, there is no single entry point that calls all instances from the same entry point (for example, service level), which would make an easy target for the spring transactional tag.

Now the question is: is it possible to solve this problem with the help of aspects? If so, what could be the main approach? Thank you

+4
source share
3 answers

You do not need a single entry point, but you need the ability to apply a transactional interceptor to all input points so that repeated calls can participate in a single transaction. Assuming you can do this, you can accomplish this using the ThreadLocal flag and a custom implementation of org.springframework.transaction.support.TransactionSynchronization .

You must modify ZT to set the ThreadLocal flag when commit is safe to continue. In your implementation of TransactionSynchronization.beforeCommit() , which is called from PlatformTransactionManager , you can check the flag and use this to determine if the commit is allowed to continue. You can force a rollback by RuntimeException if the flag is missing.

One warning - if you have other types of transactions (that are not related to the 3 coordinating classes that you described), you need to make sure that they will not be rolled back inadvertently. To do this, you can mark this “special transaction” in A.Foo, B.Bar, and ZT with another ThreadLocal flag, and then check this flag in the guard clause in the beforeCommit() method mentioned above. Pseudocode:

 void beforeCommit() { if in special transaction if commit flag not set throw new RuntimeException("cancel transaction") end if end if end 

And, obviously, this is a hack, and I would not speak in the new system :).

+2
source

Spring Idiom would recommend having a service interface that knows about the units of work and a persistence interface that deals with relational databases. The methods in the service interface should match exactly with your use cases. The service implementation is aware of all the packages and classes of the model and persistence necessary to achieve the goals of the use case.

"Instances can call each other, and, as already mentioned, there is no single entry point that calls all instances from the same entry point (for example, the service level), which would make an easy target for the spring transaction tag."

This sentence tells me that you are doing something in a way that is not easy to deal with the spring idiom. It's hard to say exactly what you want, but it looks like you are dropping the two most important layers that spring recommends. If it seems to you that it is difficult for you to go against the grain, perhaps this is your design that needs to be further developed.

"... different subscribers with different classes between ..." - perhaps you need to declare transactions individually for these subscribers.

You can declare transactions in an XML configuration using aspects, either using spring AOP or AspectJ. spring 2.5 and above now give you the option to use annotations if you prefer them in your XML configuration.

Your description is terribly confusing. Perhaps this is part of the reason you are having difficulty with this. I would review or clarify.

+1
source

With spring and aop transactions, you can do this, but it will be a little "hack" ...

You will need to place the start of the transaction at all entry points - you can only make transactions after the start of the transaction, and you will need a second aspect within this to control whether to commit or not.

Now, the only way to tell spring to cancel the transaction is to throw an exception on the transaction boundary. Thus, what you will need to do if you enter the area Z that will cause the commit, you will need to put something in the stream locally (also possible through the aspect), which this "internal" aspect will find and therefore will not throw an exception to roll back a transaction. If you do not enter Z, then the local thread will not receive the flag, and when you return on the internal aspect, the exception will be thrown to cancel the transaction. You may have to catch this exception.

0
source

Source: https://habr.com/ru/post/1286243/


All Articles