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

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

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.

Generic Repository in Spring JPA

We are working on a Restful project with lots of DB tables. Though the operations on the tables are almost same and mainly INSERT/UPDATE/DELETE/FETCH.
my questions is:
will we have to create a repository (extending JpaRepository) for every entity (Domain class) we create or, there is an option of creating a GenericRepository that can handle all the above-mentioned functionalities for all the entities?
i.e a single GenericRepository for all.
if so, could you share an example?
is [there] an option of creating a GenericRepository that can handle all the above-mentioned functionalities for all the entities?
You are looking at this with a wrong assumption: You are really not supposed to have a repository per table/entity but per Aggregate(Root). See Are you supposed to have one repository per table in JPA? for more details.
Second: Having a generic repository kind of defies the purpose of Spring Data JPA, after all, JPA already has a generic repository. It's called EntityManager. So if you just need the operations you mentioned, just injecting an EntityManager should be fine. No need to use Spring Data JPA at all. And if you want to have something between your business code and JPA specifics, you can wrap it in a simple repository as described by #AlexSalauyou.
One final point: You'll have the code to create all the tables somewhere. You'll also have the code for all the entities. And you have the code for testing this. Is having a trivial interface definition for each going to be a problem?
For insert/update/delete operations such repository may be as simple as:
#Component
public class CommonRepository {
#PersistenceContext
EntityManager em;
#Transactional
public <E> E insert(E entity) {
em.persist(entity);
return entity;
}
#Transactional
public <E> E update(E entity) {
return em.merge(entity);
}
#Transactional
public void delete(Object entity) {
em.remove(entity);
}
}
For more accurate code, refer SimpleJpaRepository implementation

Ordering Spring proxies without AspectJ

#Service
#Transactional
public CarService {
#Autowired private CarRepository carRepository;
#Cachable("cars")
public List<Car> getCars() {
return carRepository.getAll();
}
}
Suppose I have a code like this, where both #Transactional and #Cachable are presented. How can I guarantee that proxy chain spring will go through will be proxyForCache-proxyForTransaction? I.e. transaction won't be created, if my application already has cached result. I've seen a lot of examples, where people offer to implement Ordered interfaface on a class-level, namely, on #Aspect level. But problem is we don't use AspectJ in our project. Is there any way to order spring proxies without creating additional classes or at least using of AspectJ?

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

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.

EntityManager and two DAO with PersistenceContextType.EXTENDED

I have a problem with my entity manager in my application. I have two DAO clasess like this:
#Repository
public abstract class DaoA
{
protected ClassA persistentClass;
#PersistenceContext(name="my.persistence", type=PersistenceContextType.EXTENDED)
protected EntityManager entityManager;
-------------- some typical action for DAO --------------
}
Second DAO is for ClassB and looks similar to DaoA. The rest of things are done for me by the Spring framework.
When I'm debugging the application I recognize that both DAO objects have different instances of EntityManager. In the result my two different DAOs are connected with different PersistenceContext.
Question is if this is correct behaviour or not? I would like to have the same PersistenceContext for all my DAO classes. Please give me a hint if this is possible and if I understood the JPA correctly?
Regards Hsd
It's a correct behaviour of EXTENDED persistence context, therefore you don't need it to be EXTENDED in this case.
In most cases you need a TRANSACTIONAL persistence context, that is the default mode when type is omitted:
#PersistenceContext(name="my.persistence")
protected EntityManager entityManager;
In this mode persistence context is associated with the transaction, so that all DAOs will share the same persistence context when working inside the same transaction. I guess it's what you need.

Resources