Does it make sense to use Spring's #Transactional annotation in a method which doesn't talk to database? - spring

I am trying to understand a project which involves spring's declarative transactional annotation. The body of the function is not making any JDBC calls or calling JPA repository methods. All it is doing is call some third party API and transform it's results, it's not even saving the response in the database. So no database interactions at all.
My question is that is it worth using #Transactional annotation on this method? Because as per my understanding #Transactional only helps in maintaining consistency in databases.

The #Transactional annotation defines the scope of a single database transaction - all it does is it begins the transaction and either commit it or rollback. It allows to manage transaction declarative way rather than do it programatically every time.
It looks something like this:
UserTransaction utx = entityManager.getTransaction();
try {
utx.begin();
// your method invocation here
utx.commit();
} catch(RuntimeException ex) {
utx.rollback();
throw ex;
}
By making method #Transactional when there is no database calls you only make its performance worse as redundant steps have to take place when not necessary.

Related

Not using #Transactional and calling persistence layer methods

I have my services like this annotated with #Transactional
#Transactional
#Service
public class Contact_Service {
....
In my Controller i don't have #Transactional and sometimes i use some persistence layer methods directely to search and persist my object and everything is okey :
#Controller
public class GestionAO {
....
#RequestMapping(...)
public String alerte() {
contact_respository.findOne(...) ;
...
contact_respository.save(...) ;
My question since my controller is not in a transaction will i got some problems ?
Can my object don't get saved in some cases ?
Will i got concurrence problem ?
Looks fine now when you have only one save call. If there are multiple DML or DDL operations executed from the Controller you will lose on not having transaction management. You will lose on the ACID behavior that transactions offer.
The purpose of having #Transactional annotation is to perform multiple database operations in a single transaction. If one operation fails, entire transaction should be roll-backed. Otherwise this can cause data integrity issues.
And the most important thing is to have #Transactional on service layer methods. Because that's one layer who knows unit of work and use cases. In some cases you will have to call multiple DAO layer methods, those all operations are called from service layer and mostly from single method. So it is always better to annotate your service layer methods as #Transactional.
To sum it up, You must have #Transactional annotations on service layer methods.
you should only annotate service with #Transactional. to make sure all of db operations under single transaction, it is recommended to add a new method in service which contains all you db operations, and just call this new method in controller.

Do Spring transactions propagate through new instantiations

I'm working on a bunch of legacy code written by people before me and I'm confused about a particular kind of setup and wonder if this has ever worked to begin with.
There is a managed bean in spring that has a transactional method.
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public boolean updateDraftAndLivePublicationUsingFastDocumentsOfMySite(List<FastDocumentLite> fastDocumentLites, Long mySiteId) throws Exception { ... }
Now inside that method I find new instantiations calling update methods fe:
boolean firstFeed = new MySiteIdUpdate(publishing, siteDao, siteDomainService).update(siteId, fastDocumentLites.get(0).getMySiteId());
From my understanding on IOC this new class isn't managed by spring , it's just a variable in the bean. Now going further inside the update method you see another service gets called.
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void activateSubdomainForSite(Long siteId, boolean activationOfSite)
So if there is a transaction open it should be propagated into this service. But here is what I don't get if that MySiteIdUpdate object isn't managed by spring does the first transaction move forward to the activateSubdomainForSite method ?? Or is another transaction being opened here. I looked in the logs and I believe it to be the latter but I rather ask the experts for a second oppinion before I proclame this legacy code to be complete rubbish to the project lead. I'm suffering with a StaleStateException somewhere further down the road and I'm hoping this has anything to do with it.
I think the code is correct, and the second #Transactional should reuse the existing transaction.
Because:
1) Spring Transaction handling is done either by Proxies or by AspectJ advices. If it is done by Proxies then it is required that MySiteIdUpdate invoke an instance that is injected (this is what you did). If you use AspectJ, then it should work anyway.
2) The association Transactions to the code that use is done by the Thread, this mean, as long as you "are" in the thread which started the transaction you can use it. (you do not start an new thread, so it should work)
An other way to explain: It is perfect legal when you have some method in your call hierarchy that does not belong to an spring bean. This should not make the transaction handling fail.

Hibernate 4 + Spring 3.2 + Transaction : One Service, Several Dao , One Method

I'm a beginner in hibernate 4 & Spring 3.2 stuffs.
I have read some tutorials and discussion on stack but i don't find a clear answer to my questions. And i think the best way to understand is to ask and share knowledges !
Here we go!
So you create each time a Pojo, a Dao , a Service class, with methods annotated transactionnal. That's ok. I'm using Sessionfactory to handle my transaction. I'm looking for good practices.
1- If you want to use Delete Method and Save Method from the same Service, how will you do to make it works in a same transaction. When i look at the log, each method are executed in different transactions.
This SampleServiceImpl:
#Transactional
public void save(Sample sample){
sampleDao.save(sample);
}
#Transactional
public void delete(Sample sample){
sampleDao.delete(sample);
}
// A solution could be that , but not very clean...there should be an another way, no?
#Transactional
public void action(Sample sample){
sampleDao.save(sample);
sampleDao.delete(sample);
}
2- If you want to use Delete Method and Save Method from different Services class, how will you do to make it works in a same transaction. Because each method in each service class is handled by a Transactionnal annotation. Do you create a global Service calling all subservice in one method annoted Transactional
SampleServiceImpl:
#Transactional
public void save(Sample sample){
sampleDao.save(sample);
}
ParcicipantServiceImpl
#Transactional
public void save(Participant participant){
participantDao.save(participant);
}
// A solution could be that , but not very clean...there should be an another way, no?
GlobalServiceImpl
#Transactional
public void save(Participant participant,Sample sample){
participantDao.save(participant);
sampleDao.save(sample);
}
3- And the last question but not the least .If you want to use several Methods from severals service in one global transaction. Imagine you want to fill up 5 or more table in one execution of a standalone program. How is it possible because each Service to have his proper transactional method, so each time you called this method, there is a transaction.
a- I have successfully arrive to fill up two tables in a sample transaction using Mkyong tutorial and cascade property in the mapping. So i see how to make it works for one table directly joined to one another or more tables.
b- But if you have a 3 tables Participant -> Samples -> Derived Products. How will you fill up the three tables in a same transaction.
I don't know if i'm clear. But i would appreciated some help or example on that from advanced users.
Thanks a lot for you time.
Your solution is fine, maybe this works if you want to using nested transactional methods(note I saw this solution couple days ago and didn't test it):
< tx:annotation-driven mode="aspectj" / >
< context:load-time-weaver aspectj-weaving="on"/ >
#Transactional
public void action(Sample sample){
save(sample);
delete(sample);
}
Transaction should propagate.
GlobalServiceImpl
#Transactional
public void save(Participant participant,Sample sample){
participantDao.save(participant);
sampleServiceImpl.save(sample);
}
The approch you are following is cleaner approch,
ServiceOpjects are ment to contain business logic. Hence they will always manuplate through data objects.
What we do in practise is create a another layer that uses dataObjects and and other functional call of same layer. Then this all business layer is called via service layer having annotation #transactional.
Can you please mention why you think this approch is dirty??

#Transactional Annotation + for a data insertion in a loop

I am using Spring 3, JPA + Hibernate for a CMS application. In that application I have a service class method which is annotated with #Transactional Annotation with rollBack property. Inside that method I am inserting data (ie entity classes) to a table using a loop. For each iteration of the loop entity classes has to be saved to the database. But it is not happening. The commit only happens when the execution of the loop has completed and exits from the method. Then it commits and saves all at once. But I need to read data once it gets inserted into the database before committing in this case. I tried with the ISOLATION LEVEL to read uncommitted but it didn't supported since I am using the default JPADialect. Also tried to add the hibernate implementation of jpaDialect but still it didn't worked. Please help with a workaround for this problem. One more thing, is there any way using propagation required method.
You are right, this is what I stands for in acid. Because the transactions are working in isolation, other transactions cannot see them before they are committed. But playing with isolation levels is a bad practice. I would rather advice you to run each and every iteration in a separate transaction with start and commit inside.
This is a bit tricky in Spring, but here is an example:
public void batch() {
for(...) {
insert(...)
}
}
//necessarily in a different class!
#Transactional
public void insert() {
}
Note that batch() is not annotated with #Transactional and insert() has to be in a different class (Spring service). Too long to comment, but that's life. If you don't like it, you can use TransactionTemplate manually.
remove the transactional annoation on the the method with loop.
In the loop call a separate method to perform the save, make that method transactional
You either need to go with programmatic transactions (Spring's TransactionTemplate or PlatformTransactionManager are the classes to look at, see Spring Doc for programmatic transactions, or you can call another transactional method from within your loop where the transaction is marked with Propagation.REQUIRES_NEW, meaning each call of that method is executed in its own transaction, see here. I think that the second approach requires you to define the REQUIRES_NEW method on a different Spring bean because of the AOP-Proxy. You can also omit the REQUIRES_NEW if the loop is not executed within a transaction.

How to manage transactions with JAX-RS, Spring and JPA

I'm using JAX-RS to provide an HTTP-based interface to manage a data model. The data model is stored in a database and interacted with via JPA.
This allows me to modify the interface to the data model to suit REST clients and mostly seems to work quite well. However, I'm not sure how to handle the scenario where a method provided by a JAX-RS resource requires a transaction, which affects the JPA get, update, commit-on-tx-end pattern, because there is only a transaction wrapping the get operation, so the update is never committed. I can see the same problem occurring if a single REST operation requires multiple JPA operations.
As I'm using Spring's transaction support, the obvious thing to do is to apply #Transactional to these methods in the JAX-RS resources. However, in order for this to work, Spring needs to manage the lifecycle of the JAX-RS resources, and the useage examples I'm aware of have resources being created via `new' when needed, which makes me a little nervous anyway.
I can think of the following solutions:
update my JPA methods to provide a transaction-managed version of everything I want to do from my REST interface atomically. Should work, keeps transactions out of the JAX-RS layer, but prevents the get, update, commit-on-tx-end pattern and means I need to create a very granular JPA interface.
Inject Resource objects; but they are typically stateful holding at least the ID of the object being interacted with
Ditch the hierarchy of resources and inject big, stateless super resources at the root that manage the entire hierarchy from that root; not cohesive, big services
Have a hierarchy of injected, stateless, transaction-supporting helper objects that 'shadow' the actual resources; the resources are instantiated and hold ths state but delegate method invocations to the helper objects
Anyone got any suggestions? It's quite possible I've missed some key point somewhere.
Update - to work around the lack of a transaction around the get, update, commit-on-tx-close flow, I can expose the EntityManager merge(object) method and call it manually. Not neat and doesn't solve the larger problem though.
Update 2 #skaffman
Code example:
In JPA service layer, injected, annotations work
public class MyEntityJPAService {
...
#Transactional(readOnly=true) // do in transaction
public MyEntity getMyEntity(final String id) {
return em.find(MyEntity.class, id);
}
In JAX-RS resource, created by new, no transactions
public class MyEntityResource {
...
private MyEntityJPAService jpa;
...
#Transactional // not injected so not effective
public void updateMyEntity(final String id, final MyEntityRepresentation rep) {
MyEntity entity = jpa.getMyEntity(id);
MyEntity.setSomeField(rep.getSomeField());
// no transaction commit, change not saved...
}
I have a few suggestions
Introduce a layer between your JPA and JAX-RS layers. This layer would consist of Spring-managed #Transactional beans, and would compose the various business-level operations from their component JPA calls. This is somewhat similar to your (1), but keeps the JPA layer simple.
Replace JAX-RS with Spring-MVC, which provides the same (or similar) functionality, including #PathVariable, #ResponseBody, etc.
Programmatically wrap your JAX-RS objects in transactional proxies using TransactionProxyFactorybean. This would detct your #Transactional annotations and generate a proxy that honours them.
Use #Configurable and AspectJ LTW to allow Spring to honour #Transactional even if you create the object using `new. See 8.8.1 Using AspectJ to dependency inject domain objects with Spring

Resources