Introduction
In a basic data query instance, you can implement a crudrepository interface for a query or a combination of multiple fields query, but only if the conditions are relatively simple, if the conditions are more complex, then the name of a method will be very long, Then you can implement the data query in a different way, such as the criteria API, specification, query DSL, which is about to be mentioned below.
Criteria Apicriteriaquery
A typical query code is as follows:
LocalDate today = new LocalDate();CriteriaBuilder builder = em.getCriteriaBuilder();CriteriaQuery<Customer> query = builder.createQuery(Customer.class);Root<Customer> root = query.from(Customer.class);Predicate hasBirthday = builder.equal(root.get(Customer_.birthday), today);Predicate isLongTermCustomer = builder.lessThan(root.get(Customer_.createdAt), today.minusYears(2); query.where(builder.and(hasBirthday, isLongTermCustomer));em.createQuery(query.select(root)).getResultList();
The main steps are as follows:
- To create a query builder
CriteriaBuilder
- Instantiate a conditional query
- Create a root element of a query
- Create conditional predictions for one or more queries
entityManager
executing a query on
Criteriaupdate/criteriadelete
CriteriaQuery
Is the interface introduced by JPA 2.0, and in JPA 2.1 it introduces CriteriaUpdate
and CriteriaDelete
interfaces for modifying and deleting data.
CriteriaUpdate
Implementation and CriteriaQuery
similar, its implementation is as follows:
CriteriaBuilder builder = entityManager .getCriteriaBuilder();CriteriaUpdate<T> update = builder .createCriteriaUpdate(postModerateClass);Root<T> root = update.from(postModerateClass);Expression<Boolean> filterPredicate = builder.like( builder.lower(root.get("message")), "%spam%");if(Post.class.isAssignableFrom(postModerateClass)) { filterPredicate = builder.or( filterPredicate, builder .like( builder.lower(root.get("title")), "%spam%" ) );}update.set(root.get("status"), PostStatus.SPAM).set(root.get("updatedOn"), new Date()).where(filterPredicate);return entityManager.createQuery(update).executeUpdate()
Of course, if you feel that it is difficult to write so many template code, you can also directly through EntityManager
the createQuery
interface of handwritten SQL, is also possible. There are other methods, such as the following Specification
interface.
Specification interface
Specification
The interface implements a reusable prediction (predicate), an Specification
interface is a query condition that can be created by creating multiple Specification
interfaces to implement complex conditional queries with the following interfaces:
public interface Specification<T> { Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb);}
Root
, CriteriaQuery
as CriteriaBuilder
Criteria
in, here is an example:
public CustomerSpecifications { public static Specification<Customer> customerHasBirthday() { return new Specification<Customer> { public Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) { return cb.equal(root.get(Customer_.birthday), today); } }; } public static Specification<Customer> isLongTermCustomer() { return new Specification<Customer> { public Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) { return cb.lessThan(root.get(Customer_.createdAt), new LocalDate.minusYears(2)); } }; }}
In order for repository to execute this query, the repository interface is required to implement the JpaSpecificationExecutor
interface. The query instance is as follows:
customerRepository.findAll(hasBirthday());
or implement a combined query (a Help method such as where, and, or, is provided in JPA to simplify the operation):
customerRepository.findAll(where(customerHasBirthday()).and(isLongTermCustomer()));
Querydsl
Open Source Project QUERYDSL also provides a simplified template code implementation, you need to pom.xml
add QUERYDSL package, and then add plug-ins to implement the automatic creation of query classes under each source package such as QCustomer
.
<plugin> <groupId>com.mysema.maven</groupId> <artifactId>maven-apt-plugin</artifactId> <version>1.0</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources</outputDirectory> <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor> </configuration> </execution> </executions></plugin>
The query code is as follows:
BooleanExpression customerHasBirthday = customer.birthday.eq(today);BooleanExpression isLongTermCustomer = customer.createdAt.lt(today.minusYears(2));customerRepository.findAll(customerHasBirthday.and(isLongTermCustomer));
Where booleanexpression and specification are similar, of course, repository need to implement the appropriate interface
public interface CustomerRepository extends JpaRepository<Customer>, QueryDslPredicateExecutor {}
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
https://vladmihalcea.com/jpa-criteria-api-bulk-update-delete/
Spring Data Jpa