In Spring 3.2, should we use #Transactional annotation for db activities? - spring

I use spring 3.2 and Hibernate 4 in my project. When i query table i get a "No Session found for current thread" message. I try to use #Transactional annotation(it get success) but i don't want to put #Transactional to every service implementation.
Is there an another way?
In other words "How can i do a simple "insert" operation without using #Transaction?"
Thx...

You should not have #Transactional on you DAO methods, in fact you should never be accessing your DAO methods directly, you should be using an #Service. A service will use zero or more DAO classes to perform operations, only after all operations are completed will the transaction be committed.
#Repository
public class CustomerDao() {
// dao methods here, they are not transactional but will be run within a sevice transaction
}
#Service
#Transactional
public class CustomerService() {
private final CustomerDao customerDao;
#Autowired
public CustomerService(CustomerDao customerDao) {
this.customerDao = customerDao;
}
//service methods here (they are all transactional because we have annotated the class)
}

#Transactional is used for making a java code call in transaction so that in case any exception occurred during the process then all database changes will be rolled back. In ideal scenario every service which you think should be independent should have #Transactional annotation. Hibernate also want each database calls in transaction thats why they have implemented in such a way that Transaction will be required for each database query to be successful. I am not sure why you wanted your service to be out of transaction still they would like to fire database calls.

Related

Why JPA Repository always create a transaction?

When I use P6Spy to capture SQL statements, I found there always a commit action takes about 200ms, which means there is always a transaction.
After more research, I found JPA always creates a transaction.
JPA always create a transaction even for findById method.
JPA always create a transaction even when explicitly annotate a method with "#Transactional(propagation = Propagation.NEVER)".
The root cause is SimpleJpaRepository class is annotated with #Transactional, and the
default propagation is REQUIRED.
#Repository
#Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID>
SimpleJpaRepository seems so obsessed with transaction...
Question:
Why SimpleJpaRepository add #Transactional at class level? The deleteById and delete method already annotated with #Transactional right?
How to avoid transaction for JPA query like findById?
When I hack Spring JPA source code like below, and recompiled as a home-made jar to replace the canonical jar, now JPA queries work like a charm, and for queries the commit is gone!
//Hack!
#Repository
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID>
P.S.
Related spring source codes here:
TransactionalRepositoryProxyPostProcessor.RepositoryAnnotationTransactionAttributeSource
Edit:
JPA Transaction here means JpaTransactionManager hold a physical connection with setAutoCommit(false) and follows with a commit action in the end.

is hibernate #Transactional(readOnly=true) on read query a bad practice?

I use Spring(Service Layer and Repository) to do CRUD operations on a mysql database.
MyServiceImpl :
#Service
#Transactional
public class MyServiceImpl implements MyService {
private final MyRepository myrepo;
....
#Transactional(readOnly = true)
public Optional<myObj> findOne(Long id) {
return myrepo.findById(id);
}
}
is the using of readonly=true for read operations a bad practice? what about performance?
This is a good optimization practice. You can find the examples in the Spring Data documentation. And you won't need to annotate your whole service with #Transactional annotation because "..CRUD methods of the Spring Data JPA repository implementation are already annotated with #Transactional"
Getting started with Spring Data JPA
To start with, since Spring doesn't do persistence itself, so readonly is only a hint to the provider for behaviour(e.g Hibernate)
As per Hibernate's behavior readonly=true will set FlushMode.NEVER in current session which will prevent committing the transaction.
If you don't explicitly set readOnly to true, you will have read/write transactions.
Now coming Back to your Question
Looking at your findOne method. Looks like you are doing a Read call from database.
So its good to mark it as readonly to let your Provider know you are reading only.
You can read more in Detail here
https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
Spring #Transactional read-only propagation

Where can I use #Transactional

Can someone explain me why this will work:
#Transactional
#Test
public void test() {
save();
}
public void save() {
Scenario scenar = new Scenario();
sessionFactory.getCurrentSession().save(scenar);
}
And this won't, because it won't find a transaction:
#Test
public void test() {
save();
}
#Transactional
public void save() {
Scenario scenar = new Scenario();
sessionFactory.getCurrentSession().save(scenar);
}
Thank you!
Spring #Transactional annotation works using Spring AOP. This means, that when a bean that contains a method with that annotation is injected as a dependency for a different bean, it gets wrapped in a proxy. This proxy has the same interface as the bean, but performs additional actions before a method is invoked (wrapping it in a transaction in this case). You can think of it as a sort of a decorator. You can even see the proxy being invoked when you debug your application.
Now, when the method that you annotate with #Transactional is called from the same class, there is no (at least, no easy) way to inject the proxy. There just isn't a way to replace the object referenced by the "this" keyword in Java.
More reading on Spring AOP proxies.
As you have a method annotated as #Test I assume this is part of a Junit Test class.
Spring developpers know that test methods usually do not implement interfaces, and as such cannot support JDK proxying. So they specially support #Transactional annotation on a #Test method. The doc says :
Enabling and disabling transactions
Annotating a test method with #Transactional causes the test to be run within a transaction that will, by default, be automatically rolled back after completion of the test. If a test class is annotated with #Transactional, each test method within that class hierarchy will be run within a transaction. Test methods that are not annotated with #Transactional (at the class or method level) will not be run within a transaction. Furthermore, tests that are annotated with #Transactional but have the propagation type set to NOT_SUPPORTED will not be run within a transaction.

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.

Accessing Spring #Transactional service from multiple threads

I would like to know if the following is considered safe.
Usual Spring service class that accesses a bunch of DAOS / hibernate entities:
#Transactional
public class MyService {
...
public SomeObject readStuffFromDB(String key) {
...
//return some records from the DB via hibernate entity etc
}
A class in the application that has the service wired in:
public class ServiceHolder {
private MyService myService;
private SomeOtherObject multiThreadedMethod() {
...
//calls myService.readStuffFromDB() and uses the results
//to return something useful
}
multiThreadedMethod will be called from multiple threadpool threads. I would like to know if the multiThreadedMethod is safe in its calls to myService.
It is NOT making any modifications to the DB - only reading.
What happens if two threads call myService.readStuffFromDB() at exactly the same time? Will a concurrent modification exception be thrown from somewhere?
I've been running it with no issues but I'm not 100% sure it will always work.
Yes you will call the same object in the same time as long as your service bean is defined as singleton (which is default and proper), but you should not rely on local variables in you services. So the methods should be written that way they can work independently (you don't need a mutual exclusion here). If you called db and tried do any operations nothing would happen because every thread would receive a new instance of entity manager. If you modified db in the same time and any type of db exception was thrown you would get a rollback exception which is perfectly fine.
entityManager.persist() will do more or less entityManager.getEntityManagerAssignedToCurrentThread().persist()
It is a proxy not real object. So you are safe :)

Resources