Which is faster custom query using #Query vs findAll() thru CrudRepository? - java

I was writing Java code to get all the rows from the database table.
I was using CrudRepository and used this method below.
public interface StudentRepository extends CrudRepository<Student, Long>
{
public List<Student> findById(long id);
}
or
#Query(value = "SELECT s FROM Student s")
List<Student> customMethod(long id);
Which method is faster? Does Java internal method provide faster than our custom query?
Thanks in advance.

The default findById provided by Spring Data Repository and a query-annotated method have significantly different semantics. But, to keep it short, I will try to focus on differences in performance exclusively.
Unless you have query cache enabled, a query-annotated method will always hit the database with a query.
findById, on the other hand, ultimately calls EntityManager.find(). EntityManager.find() looks up the entity in the persistence context first. That means if the entity has already been loaded into the context, the call will not hit the underlying database.
As a side note, if you're curious as to how Spring implements the default repository methods, have a look at the source of SimpleJpaRepository.

You have to understand that findAll() method eventually generates the query for the selection. The only way to prove that is to test it. I don't think you will gain a significant performance boost. JPA's, on another hand, query generation is extremely easy to understand and use. So, if you hesitate between using one or the other, I would stick to findAll() JPA or spring data repository methods.

Related

How query method of Spring Data JPA generate query?

When a method is created under a specific rule of Spring Data JPA, a method that calls the corresponding query is created.
For example,
public interface CustomerJpaRepository implements JpaRepository<Customer, Long>{
public List<Customer> findByName(String name);
}
findByName() generate the query similar to one below.
select * from Customer where name = name;
I am curious about this principle. To be precise, I'm curious about the code that parses this method and turns it into a query.
I looked at the code of the SimpleJpaRepository class that implements JpaRepository, but could not find a clue. (Of course, there is a possibility that I did not find it).
In summary, when a method consisting of specific words is declared in JpaRepository, I am curious about the code that actually executes this method internally. More specifically, I'd like to see the code that makes this method works.
If there is no code to do this internally (I personally doubt it's possible...), I want to know how it is implemented in detail, if there is a link or material that explains the principle or internal process, please share related references.
The parsing logic for creating queries from spring-data repository method names is currently mainly declared in the package org.springframework.data.repository.query.parser.
Basically, a repository method name string is parsed into a PartTree, which contains Parts representing defined abstract query criteria.
The PartTree can then be used to create a more specific query object, e.g. with a JpaQueryCreator, or a RedisQueryCreator, depending on the type of repository.
I recommend you to check this Query Creation spring doc
It explains the rules of how the method convert into a query.

Not Equals Query on Spring Boot REST/JPA Service

I'm brand new to Spring Boot, and I've created a very basic REST service that uses JPA, and exposes the RepositoryRestResource for CRUD and query operations on my model:
#RepositoryRestResource
public interface CatalogueOrderRepository extends JpaRepository<CatalogueOrder, Long>,
QuerydslPredicateExecutor<CatalogueOrder> {
}
Using this, I'm able to perform queries that involve searching for values, pagination, and ordering, for instance:
?page=0&size=5&sort=priority,desc&orderStatus=submitted
Is it possible to search for values that are not equal, without any additional work? For instance, all orders where the orderStatus is NOT equal to 'submitted'.
I notice that the Predicate interface has a not() method, though I'm not sure if it's related.
For such cases you should do some work. There are different approaches to do that. See Spring docs and examples about JPA.
E.g. you can use #Query or specifications.
You can try "Query creation from method names".
Let's say you want to search Orders by orderstatus <> submitted,
List<Order> findByOrderstatusNot(String orderstatus);

Spring JPA Hibernate DeleteByColumnName behaves very inefficient

I was trying to use the Spring's CrudRepository work with Hibernate to delete rows by a non-primary-key column, using deleteByColumnName method. However, the actual executed query is very inefficient and too slow in practice.
Suppose I have two tables Project and Employee, and each employee is in charge of some projects, which implies that the Project table has a field employee_id. Now I would like to delete some projects by employee_id. I wrote something like
public interface ProjectRepository extends CrudRepository<Project, String> {
#Transactional
void deleteByEmployeeId(String employeeId);
}
What I am expecting is Hibernate will execute the following query for this method
DELETE FROM Project
WHERE employee_id = ?
However, Hibernate executes it in a drastically slow way like
SELECT id FROM Project
WHERE employee_id = ?
Hibernate stores the above result in a list, and execute
DELETE FROM Project
WHERE id = ?
for N times... (it executes in batch though)
To address this inefficiency problem, I have to override the method by writing SQL directly, like
public interface ProjectRepository extends CrudRepository<Project, String> {
#Query("DELETE FROM Project p where p.employee_id = ?1")
#Modifying
#Transactional
void deleteByEmployeeId(String employeeId);
}
Then the behavior will be exactly the same as what I am expecting.
The performance is substantially distinct when I delete about 1k rows in a table containing around 500k entries. The first method will take 45 seconds to finish the deleting compared to the second methods taking only 250ms!
The reason I use Hibernate is taking advantage of its ORM strategy that avoids the use of SQL language directly, which is easy to maintain in the long run. At this point, is there anyone who know how to let Hibernate execute the deletion in the manner of my second method without directly writing the SQL? Is there something I am missing to optimize the Hibernate performance?
Thanks in advance!
Here you can find a good explanation why Hibernate has this bad performace when deleting Project items Best Practices for Many-To-One and One-To-Many Association Mappings

DAO, Spring and Hibernate

Correct me if anything is wrong.
Now when we use Spring DAO for ORM templates, when we use #Transactional attribute,
we do not have control over the transaction and/or session when the method is called externally, not within the method.
Lazy loading saves resources - less queries to the db, less memory to keep all the collections fetched in the app memory.
So, if lazy=false, then everything is fetched, all associated collections, that is not effectively, if there are 10,000 records in a linked set.
Now, I have a method in a DAO class that is supposed to return me a User object.
It has collections that represent linked tables of the database.
I need to get a object by id and then query its collections.
Hibernate "failed to lazily initialize a collection" exception occurs when I try to access the linked collection that this DAO method returns.
Explain please, what is a workaround here?
Update: All right, let me ask you this. DAO is an abstract layer, so a method "getUserById(Integer id)" is supposed to return an Object.
What if in some cases I need these linked collections of the User object and in other situation I need those collections.
Are there only two ways:
1) lazy loading = false
2) create different methods: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() and inside those methods use your approach?
I mean are there only 2 ways and nothing better?
Update 2: Explain please, what would give me the explicit use of SESSIONFACTORY?
How does it look in practice? We create an instance of DAO object,
then inject it with session factory and this would mean that two consequent
method calls to DAO will run within the same transaction?
It seems to me that anyway, DAO is detached from the classes that make use of it!
The logic and transactions are encapsulated within DAO, right?
You can get the linked collection in transaction to load it while you're still within the transaction:
User user = sessionFactory.getCurrentSession().get(User.class, userId);
user.getLinkedCollection().size();
return user;
As BalusC has pointed out, you can use Hibernate.initialize() instead of size(). That's a lot cleaner.
Then when you return such an entity, the lazy field is already initialized.
Replying to your PS - is using transactions on service level (rather than DAO) level feasible? It seems to be, as doing each DAO call in separate transaction seems to be a waste (and may be incorrect).
I find that it's best to put #Transactional at the service layer, rather than the DAO layer. Otherwise, all your DAO calls are in separate hibernate sessions - all that object equality stuff won't work.
In my opinion best way to solve this problem will be to design application in a session-per-request model. Then, if you even have an object taken from DAO, until your OSIV pattern works you can use the object safely anywhere in application, even in views without bothering this stuff. This is probably better solution that those proposed because:
Hibernate.initialize() or size is a very artificial workaround - what if you want to have User with different collection initialized, would you write another method for getting user?
Service layer transactional model is OK, but the same problem comes when you want to get object extracted from the service layer to use it in controller or view
You could do something like following:
public User getByUserId(Long id, String ... fetch) {
Criteria criteria = createCriteria();
if (fetch != null) {
for (String fieldName : fetch) {
criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly
}
}
return criteria.add(Restrictions.eq("id", id)).list();
}

generic dao architecture discuss-best prastice

i thinking of doing this architecture
genericdao +interface ---> servicelayer+interface---> view layer
my dao will only have generic methods, my service layers will have real logic for instance
service layer method
string executeThis= "select c from com.abc.test.User where username =:username";
Map tempMap = new HashMap();
tempMap.put("username","abc");
return callDaoInferface.executeGenericList(executeThis,tempMap); //get from DI
Do you this this is good architecture
my question is whether suitable to move the "select.." statement from dao into service layer
Your use of interfaces is pretty much the way Spring does it, whether or not you use generic DAOs. It includes the web tier as part of the view.
I'm not crazy about your service code. The whole point of the persistence interface is to abstract SQL away from clients, yet you've let SELECT leak into your service layer. Wrong, in my opinion.
There's little or nothing object-oriented about the way you're doing things.
I'm assuming that "generic dao" means something like this.
I've done it with Spring and Hibernate. The generic DAO interface looked like this:
package persistence;
import java.io.Serializable;
import java.util.List;
public interface GenericDao<T, K extends Serializable>
{
List<T> find();
T find(K id);
List<T> find(T example);
K save(T instance);
void update(T instance);
void delete(T instance);
}
So if I have User and Book model objects, I might have two DAOs like this:
GenericDao<User, Long> userDao = new GenericDaoImpl<User, Long>(User.class);
GenericDao<Book, String> bookDao = new GenericDaoImpl<Book, String>(Book.class);
The GenericDaoImpl is either an exercise for you or will have to wait until I can post the source code.
Your architecture is just a little off.
You want a dao interface to abstract succinct db interactions, or in other words, you could implement the data access contract with various implementations, such as JPA, Hibernate, Oracle, JDBC, etc. Your queries should reside with the implementation, and you should look into named queries, which I know exists in Hibernate and JPA. Queries could be different based upon the implementation, such as db specific nuances (like MySQL's 'limit') or HQL (Hibernate Query Language) vs. SQL.
In my opinion, a service layer in most instances (like this one) is simply overhead. You would want a service for something like user authorization, where your service layer might perform some business logic to properly construct the lookup. For example, you might need to encrypt/decrypt a password, or verify that a username doesn't already exists, minimum password requirement satisfaction, etc.
Duffy's generic DAO example is pretty much the standard and I would suggest implementing a variation of that...e.g. UserDaoHibernateImpl extends GenericDao<User, Long>
Not really, no. What is the 'tempMap' doing? It seems a little weird.
Nowadays (in 2016) you should consider to use Spring Data JPA, instead of building your own Generic DAO.

Categories