Spring boot, hexagonal architecture and distributed transactions - java

In hexagonal architecture (or clean architecture), we have use cases that perform one or several interactions with infrastructure components.
These Use Cases are tipically transactional operations (we want them to be atomic).
So we would use the #Transactional annotation at Use Case method level.
#Component
#RequiredArgsConstructor
public class MyShinyUseCase implements MyShinyPrimaryPort {
private final transactionalSecondaryPort trPort1; <--- Database 1
private final anotherTransactionalSecondaryPort trPort2; <--- Database 2
#Override
#Transactional("UPS, THERE ARE 2 TRANSACTION MANAGERS IN THE CONTEXT")
public void useCaseMethod() {
trPort1.operate(); <--- Transactional resource
trPort2.operate(); <--- Transactional resource, is error I want
to rollback the trPort1.operate().
}
The problem comes when the Use Case interacts with more than one transactional resources, each of them with their TransactionManager, because the #Transactional annotation requires a specific TransactionManager to be specified, but the infrastructure specific TransactionManagers are infrastructure concerns: they should not be referenced from the domain layer, and even if we did, there are several TransactionManagers in play...
What would be the way to manage transactions involving several transactional resources in an hexagonal architecture?

Related

(DataNucleus) JDO - Service / Repository Layering and #Transactional

For personal education I am currently developing a little application framework around Guice to learn-by-doing how Spring etc. work behind the scenes.
Intro
Just for the sake of context, here is what I have so far and plan to do so you get a feeling for what I try to archive:
Context (Core)
ApplicationContext/-Configuration
Modules (auto discovered, setting up the Guice bindings)
Extensions
Config: #Config
Locale: #Locale and i18n services
Resources: #Property, #Resource and some classes providing easy access to resources
Persistence: Problems - there we go!
Question
I'd like to use the JDO standard (and its reference implementation DataNucleus) for the persistence layer. Setting up the PersistenceManagerFactory was easy, so was using it in a basic manner. I am however targeting a typical service / repository layer architecture, e.g.:
Person
PersonRepository (JDO)
PersonService (Transactions, using PersonRepository)
That alone wouldn't be too hard either, but as soon as I tried properly integrating transactions into the concept I got a bit lost.
Desired
class PersonService {
#Transactional(TxType.REQUIRED)
public Set<Person> doX() {
// multiple repository methods called here
}
}
class PersonRepository {
private PersistenceManagerFactory pmf;
public Set<Person> doX() {
try (PersistenceManager pm = pmf.getPersistenceManager()) {
pm.....
}
}
}
Difficulties
DataNucleus supports RESOURCE_LOCAL (pm.currentTransaction()) as well as JTA transactions and I would like to support both as well (the user should not have to distinguish between the two outside the configuration). He should not have to bother about transaction handling anyway, that is part of the annotation's method interceptor (I guess).
I'd love to support the #Transactional (from JTA) annotation that can be placed on service layer methods. Knowing that annotation is not per-se available in JDO, I thought it could be made usable as well.
How exactly should the repository layer "speak" JDO? Should each method get a PersistenceManager(Proxy)from the PersistenceManagerFactory and close it afterwards (as in the example) or get a PersistenceManager injected (rather than the factory)? Should each method close the PersistenceManager (in both scenarios)? That would not work with RESOURCE_LOCAL transactions I guess since a transaction is bound to one PersistenceManager.
What I tried
I have a JDOTransactionalInterceptor (working with pmf.getPersistenceManagerProxy) and a JTATransactionalInterceptor (very similar to https://github.com/HubSpot/guice-transactional/blob/master/src/main/java/com/hubspot/guice/transactional/impl/TransactionalInterceptor.java working with a ThreadLocal)
Summary
I am aware that my question may not be as clear as desired and mixes the service / repository layer questions (which is my main problem I think) and transaction stuff (which I could figure out once I understand how to properly use PMF/PM in repository layer I think)
There is no scope à la RequestScoped etc. I just want the first #Transactional method call to be the starting point for that whole thing (and that is the point: Is this impossible and the PMF/PM have to be scoped before and I have to direct my thinkings into that direction?)
Thanks for any clarification / help!

Using same jdbcTemplate for two different schemas

I have 2 datasources say dataSourceA and dataSourceB but based upon few calculations, I need to execute the same query in different schemas. Also, it is going to be executed in either of the schemas.
so, at DAO layer , I have one setDataSource() method which is #autowired to the dataSourceA, thus,returning the JDBCTemplate with former DataSource. How can I implement the dataSourceB changes using the same JDBCTemplate as it will be difficult to change at every DAO layer as entire application change will be required.
You could you inject both datasources and select the datasource inside your method according to your logic:
public class SomeDaoImpl implements SomeDao {
private final JdbcTemplate jdbcTemplateA;
private final JdbcTemplate jdbcTemplateB;
#Autowired
public SomeDaoImpl(JdbcTemplate jdbcTemplateA, JdbcTemplate jdbcTemplateB) {
// injecting both JdbcTemplate instances
this.jdbcTemplateA = jdbcTemplateA;
this.jdbcTemplateB = jdbcTemplateB;
}
public void businessLogicMethod(...) {
// choosing the actual template to be used according to your logic
JdbcTemplate jdbcTemplate = chooseTemplate(...);
// now using the template to execute a query
jdbcTemplate.execute(...);
}
}
Another option would be to instantiate two SomeDaoImpl instances and inject one JdbcTemplate into each of them, and select the DAO instance in your service layer.
But both these solutions have a flaw: transaction is usually initiated in the service layer (with an interceptor, for example), and it has no idea that you are going to route your requests to another datasource; so it could happen that a transaction starts on one datasource, but the query is executed on another one.
So the clearest solution would be to go one level up and instantiate 2 services, in each of them DAOs with different JdbcTemplate instances. Of course, 2 transaction managers will have to be configured and carefully wired (for example, via #Transactional("transactionManagerA")). More information on this here Spring - Is it possible to use multiple transaction managers in the same application?

Spring Data Transaction spanning multiple Repositories

I have the need to insert 2 different entities into 2 different tables, using the same transaction. If the second insert fails, the first one should be rolled back.
Is there any way of doing this nicely?
Pseudo code:
start tx
repo1.save(myEntity);
repo2.save(anotherEntity);
try commit
I know you can leverage #Transactioal but only on method level?
you need check that you don't have set autocommit = false.
wrap save operations into one service method and make it #Transactional. But if you use save() custom method check that save in not marked as #Transactional with propagation level required_new or nested. If you need you can use REQUIRES_NEW for saving service method to make this service method transaction independent of other transactions.
also you can wrap in with TransactionTemplate.
#Autowired
private TransactionTemplate transactionTemplate;
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
public void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
repo1.save(myEntity);
repo2.save(anotherEntity);
});
It is usually a wrong idea to have #Transactional declared around repository methods.
Repositories are only for you to access domain entities. Business logic normally involves multiple domain entities and collaborations between them.
In your architecture you should have a layer to compose business logic. This usually corresponds to a service exposed to external.
This is usually the place you should have your transaction boundary set on. Usually it is a Controller, or a Service method.
Steps to follow:
Ensure you use Interfaces for repo1 and repo2 methods as spring transactions works on proxy. ( If you use only classes, then you may need to add few other dependencies).
Annotate repo1.save(..) and repo2.save(..) with #Transactional(propagation=Propagation.REQUIRED) annotation.
Call repo1.save() from any method outside of class.
Unit test the code properly using special junit runner.

JPA Transactions and REST Services : Good practices

I am writing an application providing REST services (with Apache-CXF) that manage JPA entities (with Hibernate).
I am a bit lost with Transaction management and would like your advice on this topic.
For now, I have put an intermediate layer between my business REST services and the lower services, solely for transaction management purpose.
Currently, my code looks much like that :
#Service
class PersistanceService<MyBusinessClass>{
MyBusinessClass load(Long id);
void save(MyBusinessClass businessObject);
}
#Service
class BusinessService<MyBusinessClass>{
void doSomethingOn(MyBusinessClass businessObject);
}
#Service
class TransactionBusinessService<MyBusinessClass>{
#Transactional
void doSomethingOn(Long id) {
MyBusinessClass businessObject = persistanceService.load(id);
businessService.doSomethingOn(businessObject);
persistanceService.save(businessObject);
}
}
#Service
#path("/foo")
class RESTService {
#Path("/doSomething")
void doSomethingOn(Long id) {
transactionBusinessService.doSomethingOn(id);
}
}
I think the TransactionBusinessService is overkill. I would like ''Spring'' or ''CXF'' to handle transactions for me : I feel that a request is the good granularity to do so : Init an entity manager at the beginning of each request, and commit updates at the end.
I've tried to add the #Transactional annotation to the REST methods themselves, but it seem to be ignored, or to conflict with CXF.
Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
How can I have Spring or CXF bind the transaction management to the requests for me ?
Thanks in advance for you advice.
Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
Usually it's not good idea, because:
usually it's not that convenient to separate Transaction isolation
if you need to do some changes in for-loop, each of which has to have own transaction, it's also not
that transparent; meanwhile on service layer you may decide whether you need the whole loop to be transactional or each of iteration;
tx:annotation-driven (and some other AOP-interceptor) sometimes works a bit unpredictable, if you are using AOP annotations in the controllers directly (at least I faced such issues in Spring MVC/struts2 and some other frameworks)
So basically, you have 3 layers:
persistence layer, which is responsible for storing/fetching data only;
service layer, which is responsible for data preparation and for AOP-annotations (#Transactional, #PreAuthorize, #Cacheable and so on), which use persistence layer within;
controller level, which gets request, binds business models, probably validates it, pass model(s) to service layer and returns result from there or handles exception
How can I have Spring or CXF bind the transaction management to the requests for me?
Please make sure, that you:
you have appropriate TransactionManager ('org.springframework.transaction.PlatformTransactionManager` implementation) in your config
you have tx:annotation-driven in your config
those beans are visible in the config of your CXF services
<bean name="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>

Spring transaction internals

The situation is as follows:
Method1 has four database update methods in it. The Method1 is annotated using the Spring transaction management semantics.
Method2 has a database read method in it and it is invoked after Method1 has finished executing all its database updates. Method2 is also annotated using the Spring transaction semantics.
There's a web request that comes in, the controller intercepts the request and invokes method1 and then method2.
A transaction is wrapped around the web-request as well.
What I am interested in knowing is:
1.How does Spring know to commit the database updates upon a successful transaction? Is there some reference to the Spring implementation that does the transaction management?
2.Since we have a hierarchy of transactions:
Transaction around the web-request->Transaction with Propagation=RequestNew for Method1->Transaction with Propagation=Required for Method2, how does Spring do the transaction management to ensure the transactions are executed within the proper context with the right order?
In short, it will be great to get a play by play account of how Spring performs the transaction management in all its grittiest details or a reference to documentation that doesn't simply hand-wave an explanation centered around JTA or some other acronym.
Thanks
Lets make some basic statements.
A transactional context is an environment where some special properties (database session) are made available to the application runtime which are otherwise not available. A Transaction Context is generally used to scope a transaction.
Spring uses, AOP Proxies and XML metadata to achieve a Declarative transaction management.
Annotations are used to mark the Transaction Propagation behavior of a particular method.
Spring uses Interceptor Mechanism to apply the transaction over the methods.
Here I am reusing the example give by #stacker above
MyClass{
#Transactional
public void sequence() {
method1();
method2();
}
#Transactional
void method1() {
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
void method2() {
}
}
You can also achieve the same functionality using xml configuration as well. Lets take this as its popular and widely used.
At the time of deployment
Spring framework checks the xml configuration files (famed applicationContext.xml) and depending on the configuration, scans the code for #Transactional annotation (assuming that the configuration is mentioned as annotation based).
After this, it generates AOP proxies for methods marked for transaction. In simple terms, these proxies are nothing but wrapper around the concerned methods.
Within these wrapper methods, before and after a Transaction Advisor code is also generated depending on the configuration (namely the transaction propagation).
Now when these wrapper methods are invoked Transaction Advisor comes into picture before and after the actual method call. .
Representing the same in pseudo code for the example above
ProxyMyClass{
MyClass myclass;
.
.
.
sequence(){
//Transaction Advisor code (Typically begin/check for transaction)
myclass.sequence();
//Transaction Advisor code(Typically rollback/commit)
}
.
.
.
}
This is how spring managers the transaction. A slight oversimplification though.
Now to answer your questions,
.How does Spring know to commit the database updates upon a successful transaction? Is there some reference to the Spring implementation that does the transaction management?
Whenever you call a method under transaction, you actually call a proxy which first executes the transaction advisor (which will begin the transaction), then you call the actual business method, once that completes, another transaction advisor executes (which depending on way method returned, will commit or rollback transaction).
Since we have a hierarchy of transactions: Transaction around the web-request->Transaction with Propagation=RequestNew for Method1->Transaction with Propagation=Required for Method2, how does Spring do the transaction management to ensure the transactions are executed within the proper context with the right order?
In case of transaction hierarchy, the spring framework generates the Transaction Advisor checks accordingly. For the example you mentioned,
for method1 (RequestNew ) Transaction Advsor code (or transaction Advice) would be to create a new transaction always.
for method2 (Required ) Transaction Advisor code (or transaction Advice) would be check for existing transaction and use the same if it exists or else create a new transaction.
There is an image on the spring documentation page which very nicely summarizes these aspects.
Hope this helps.
Controller
#Transactional
public void sequence() {
method1();
method2();
}
#Transactional
void method1() {
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
void method2() {
}
The default propagation is REQUIRED (Support a current transaction, create a new one if none exists.) Therefore m1 will use the Transaction started in the Controller. m2 is annotated as REQUIRES_NEW ( Create a new transaction, suspend the current transaction if one exists.) The order of the transaction is the order you call the transactional methods.
Controller
begin tx1
|--------------------> m1 (uses tx1)
|
| begin tx2
|--------------------> m2 (uses tx2)
| commit tx2
commit tx1
Have you read the Spring documentation? Basically AOP is used to manage the transaction. You should also read the AOP documentation. If the AOP documentation is not enough I suggest you go through the code. Stepping through the code in debug mode with break-point would be good.

Categories

Resources