In the last article SpringBoot (ii) : Web integrated development briefly introduced the basic use of Spring Data JPA, this article will be more comprehensive introduction to spring data JPA common usage and matters needing attention

When using Spring Data JPA development, I found that there are few articles in China that comprehensively introduce Spring Boot JPA and cases are fragmentary, so I wrote an article to summarize. I am also translating the Spring Data JPA reference guide. If you are interested, please contact me and join in the translation!


Introduction to Spring Data JPA

First, what is JPA?

JPA(Java Persistence API) is an official Java Persistence specification proposed by Sun. It provides Java developers with an object/association mapping tool to manage relational data in Java applications. Its main purpose is to simplify the existing persistence development work and integrate ORM technology, ending the current situation of Hibernate, TopLink, JDO and other ORM frameworks operating separately. It is worth noting that JPA is developed on the basis of fully absorbing existing ORM frameworks such as Hibernate, TopLink and JDO, which has the advantages of easy to use and strong scalability. JPA has received great support and praise from the development community so far, including the Spring and EJB3.0 development teams.

Note :JPA is a specification, not a product, so Hibernate,TopLink,JDO are a set of products, if these products implement the JPA specification, then we can call them implementation products of JPA.

spring data jpa

Spring Data JPA is a set of JPA application framework encapsulated by Spring based on ORM framework and JPA specification, which enables developers to access and operate Data with minimal code. It provides common functions including add, delete, change, check, etc., and easy to expand! Learning and using Spring Data JPA can greatly improve your development efficiency!

Spring Data JPA frees us from the DAO layer, and basically all CRUDS can rely on it for implementation


The basic query

Basic queries are also divided into two types, one is that Spring Data is implemented by default, and the other is automatically parsed into SQL according to the method of query.

Pre-generated method

Spring Data JPA pre-generates some basic CURD methods by default, such as add, delete, modify, and so on

1 inheritance JpaRepository

public interface UserRepository extends JpaRepository<User.Long> {}Copy the code

2 Use the default method

@Test
public void testBaseQuery(a) throws Exception {
    User user=new User();
    userRepository.findAll();
    userRepository.findOne(1l);
    userRepository.save(user);
    userRepository.delete(user);
    userRepository.count();
    userRepository.exists(1l);
    // ...
}Copy the code

I’m not going to explain it because you can see what it means by the method name

Customize simple queries

Custom simple query is generated automatically according to the method name, SQL syntax is largely findXXBy, readAXXBy, queryXXBy, countXXBy, getXXBy behind with the attribute name:

User findByUserName(String userName);Copy the code

Also use some plus some keywords And, Or

User findByUserNameOrEmail(String username, String email);Copy the code

Modify, delete, and count are similar syntax

Long deleteById(Long id);

Long countByUserName(String userName)Copy the code

Basically, SQL system keywords can be used, such as: LIKE, IgnoreCase, OrderBy.

List<User> findByEmailLike(String email);

User findByUserNameIgnoreCase(String userName);

List<User> findByUserNameOrderByEmailDesc(String email);Copy the code

Specific keywords, use methods and production into SQL as shown in the following table

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ? 1 and x.firstname = ? 2
Or findByLastnameOrFirstname … where x.lastname = ? 1 or x.firstname = ? 2
Is,Equals findByFirstnameIs,findByFirstnameEquals … where x.firstname = ? 1
Between findByStartDateBetween … where x.startDate between ? 1 and ? 2
LessThan findByAgeLessThan … where x.age < ? 1
LessThanEqual findByAgeLessThanEqual … Where x.a ge ⇐? 1
GreaterThan findByAgeGreaterThan … where x.age > ? 1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ? 1
After findByStartDateAfter … where x.startDate > ? 1
Before findByStartDateBefore … where x.startDate < ? 1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ? 1
NotLike findByFirstnameNotLike … where x.firstname not like ? 1
StartingWith findByFirstnameStartingWith … where x.firstname like ? 1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ? 1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ? 1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ? 1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ? 1
In findByAgeIn(Collection ages) … where x.age in ? 1
NotIn findByAgeNotIn(Collection age) … where x.age not in ? 1
TRUE findByActiveTrue() … where x.active = true
FALSE findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(? 1)


Complex queries

In the actual development we need to use pagination, delete, join tables and other queries need special methods or custom SQL

Paging query

Paging query is very common in practice, spring Data JPA has helped us to achieve paging function, in the query method, you need to pass in parameter Pageable, when there are multiple parameters in the query Pageable is recommended as the last parameter

Page<User> findALL(Pageable pageable);

Page<User> findByUserName(String userName,Pageable pageable);Copy the code

Pageable is a spring encapsulation Pageable implementation class that requires the number of pages, the number of pages per page, and a sorting rule to use

@Test
public void testPageQuery(a) throws Exception {
    int page=1,size=10;
    Sort sort = new Sort(Direction.DESC, "id");
    Pageable pageable = new PageRequest(page, size, sort);
    userRepository.findALL(pageable);
    userRepository.findByUserName("testName", pageable);
}Copy the code

Limit the query

Sometimes we just need to query the first N elements, or pull the last entity.

ser findFirstByOrderByLastnameAsc(a);

User findTopByOrderByAgeDesc(a);

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);Copy the code

Customize SQL queries

In fact, Spring Data feels that most SQL can be implemented according to the method name defined, but for some reason we want to use custom SQL to query, Spring Data also perfectly supports; Use @Query annotations on SQL Query methods, including @modifying where necessary when deleting and Modifying SQL Query methods. You can also add @Transactional support for transactions, query timeout Settings, etc

@Modifying
@Query("update User u set u.userName = ? 1 where c.id = ? 2. "")
int modifyByIdAndUserId(String userName, Long id);

@Transactional
@Modifying
@Query("delete from User where id = ? 1")
void deleteByUserId(Long id);

@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ? 1")
    User findByEmailAddress(String emailAddress);Copy the code

Multi-table query

Multi-table queries can be implemented in two ways in Spring Data JPA. The first way is to use Hibernate’s cascading query to implement this, and the second way is to create a result set interface to receive the results of a join table query.

You first need to define an interface class for the result set.

public interface HotelSummary {

    City getCity(a);

    String getName(a);

    Double getAverageRating(a);

    default Integer getAverageRatingRounded(a) {
        return getAverageRating() == null ? null : (int) Math.round(getAverageRating()); }}Copy the code

The method return type of the query is set to the newly created interface

@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
        - "from Hotel h left outer join h.reviews r where h.city = ? 1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);

@Query("select h.name as name, avg(r.rating) as averageRating "
        - "from Hotel h left outer join h.reviews r group by h")
Page<HotelSummary> findByCity(Pageable pageable);Copy the code

use

Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0.10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
        System.out.println("Name" +summay.getName());
    }Copy the code

At runtime Spring automatically generates a proxy class for the interface (HotelSummary) to receive the returned results, and the code summary is retrieved using getXX


Support for multiple data sources

Multi-source support for same-origin databases

Because of the distributed development mode used in daily projects, different services have different data sources, and it is often necessary to use multiple data sources in a project. Therefore, it is necessary to configure spING Data JPA to use multiple data sources, generally divided into three steps:

  • 1 Configure multiple data sources
  • 2 Put entity classes of different sources into different package paths
  • 3 Declare different data sources and transaction support for different package paths

Here is a very clear article: Spring Boot multi-data source configuration and use

Heterogeneous database multi-source support

For example, in our project, we need to support mysql and mongodb query.

Entity class declaration @entity relational database support type, declaration @document mongodb support type, different data sources use different entities can be ok

interface PersonRepository extends Repository<Person.Long> {... }@Entity
public class Person {... }interface UserRepository extends Repository<User.Long> {... }@Document
public class User {... }Copy the code

However, if the User User uses both mysql and mongodb, it can be mixed

interface JpaPersonRepository extends Repository<Person.Long> {... }interface MongoDBPersonRepository extends Repository<Person.Long> {... }@Entity
@Document
public class Person {... }Copy the code

You can also declare different package paths. For example, mysql is used for package A and mongoDB is used for package B

@EnableJpaRepositories(basePackages = "com.neo.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.neo.repositories.mongo")
interface Configuration {}Copy the code


other

Use enumerated

When using enumerations, we want the database to store the String type of the enumeration, not the index value of the enumeration. We need to annotate the attribute with @Enumerated(enumtype.string)

@Enumerated(EnumType.STRING) 
@Column(nullable = true)
private UserType type;Copy the code

Attributes that do not need to be mapped to the database

Normally, if we put an annotation at sign Entity on the Entity class, that’s going to make the Entity class relate to the table and if there’s a property that we don’t need to associate with the database and we’re just going to do some calculation on display, we just need to put an @Transient property on it.

@Transient
private String  userName;Copy the code

Source of case

There is an open source project that uses almost all of the tags and layouts described here: CloudFavorites

reference

Spring Data JPA – Reference Documentation

Spring Data JPA — Chinese version of the Reference documentation


Like my article, please follow my official account