Spring Data - Spring Data JPA 提供的各種Repository接口


Spring Data Jpa

最近博主越來越懶了,深知這樣不行。還是決定努力奮斗,如此一來,就有了一下一波復習

演示代碼都基於Spring Boot + Spring Data JPA 

傳送門: 博主的測試代碼 

------------------------------------------------------------------------------------------------------------------------------

什么是Spring Data JPA?

Spring Data 是Spring提供的操作數據的框架在Spring data JPA是Spring data的一個模塊,通過Spring data 基於jpa標准操作數據的模塊。

Spring Data的核心能力,就是基於JPA操作數據,並且可以簡化操作持久層的代碼。

Spring Data JPA提供的核心接口

前提數據:

-- MySQL dump 10.13  Distrib 5.6.16, for debian-linux-gnu (x86_64)
--
-- Host: localhost    Database: amber
-- ------------------------------------------------------
-- Server version    5.6.16-1~exp1

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `table_user`
--

DROP TABLE IF EXISTS `table_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `table_user` (
  `id` int(11) NOT NULL DEFAULT '0',
  `name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `table_user`
--

LOCK TABLES `table_user` WRITE;
/*!40000 ALTER TABLE `table_user` DISABLE KEYS */;
INSERT INTO `table_user` VALUES (4,'tony',NULL,'shanghai',18),(5,'amber',NULL,'shanghai',18),(2,'amber1',NULL,'shanghai',18),(3,'tony',NULL,'shanghai',18),(0,'amber1',NULL,'shanghai',18),(6,'amber',NULL,'shanghai',18);
/*!40000 ALTER TABLE `table_user` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2019-01-13 13:43:57
SQL
package com.amber.pojo;

import lombok.Data;
import javax.persistence.*;

@Entity
@Table(name = "table_user")
@Data
public class User {

    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    private Integer age;
    private String address;


}
User
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>groupId</groupId>
    <artifactId>SpringBoot-JPA</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <lombok.version>1.16.20</lombok.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.8</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
pom.xml

Repository:

@org.springframework.stereotype.Repository
public interface UserRepository  extends Repository<User, Integer> {
}

 

  • 提供了方法名成查詢方式: 

    方法的名稱要遵循 findBy + 屬性名(首字母大寫) + 查詢條件(首字母大寫 Is Equals)

     findByNameLike(String name)

    findByName(String name)

    findByNameAndAge(String name, Integer age)

    findByNameOrAddress(String name) 等...

  • 基於@Query注解的查詢和更新
 /**
     * SQL nativeQuery的值是true 執行的時候不用再轉化
     * @param name
     * @return
     */
    @Query(value = "SELECT * FROM table_user WHERE name = ?1", nativeQuery = true)
    List<User> findByUsernameSQL(String name);

  //基於HQL

    /**
     * 基於HQL
     * @param name
     * @param id
     * @return
     */
    @Query("Update User set name = ?1 WHERE id = ?2")
    @Modifying
    int updateNameAndId(String name, Integer id);

CrudReposiroty : 繼承了Repository

/*
 * Copyright 2008-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import java.util.Optional;

/**
 * Interface for generic CRUD operations on a repository for a specific type.
 * 
 * @author Oliver Gierke
 * @author Eberhard Wolff
 */
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

    /**
     * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
     * entity instance completely.
     * 
     * @param entity must not be {@literal null}.
     * @return the saved entity will never be {@literal null}.
     */
    <S extends T> S save(S entity);

    /**
     * Saves all given entities.
     * 
     * @param entities must not be {@literal null}.
     * @return the saved entities will never be {@literal null}.
     * @throws IllegalArgumentException in case the given entity is {@literal null}.
     */
    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    /**
     * Retrieves an entity by its id.
     * 
     * @param id must not be {@literal null}.
     * @return the entity with the given id or {@literal Optional#empty()} if none found
     * @throws IllegalArgumentException if {@code id} is {@literal null}.
     */
    Optional<T> findById(ID id);

    /**
     * Returns whether an entity with the given id exists.
     * 
     * @param id must not be {@literal null}.
     * @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
     * @throws IllegalArgumentException if {@code id} is {@literal null}.
     */
    boolean existsById(ID id);

    /**
     * Returns all instances of the type.
     * 
     * @return all entities
     */
    Iterable<T> findAll();

    /**
     * Returns all instances of the type with the given IDs.
     * 
     * @param ids
     * @return
     */
    Iterable<T> findAllById(Iterable<ID> ids);

    /**
     * Returns the number of entities available.
     * 
     * @return the number of entities
     */
    long count();

    /**
     * Deletes the entity with the given id.
     * 
     * @param id must not be {@literal null}.
     * @throws IllegalArgumentException in case the given {@code id} is {@literal null}
     */
    void deleteById(ID id);

    /**
     * Deletes a given entity.
     * 
     * @param entity
     * @throws IllegalArgumentException in case the given entity is {@literal null}.
     */
    void delete(T entity);

    /**
     * Deletes the given entities.
     * 
     * @param entities
     * @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
     */
    void deleteAll(Iterable<? extends T> entities);

    /**
     * Deletes all entities managed by the repository.
     */
    void deleteAll();
}
CrudRepository

Crud主要是添加了對數據的增刪改查的方法

PagingAndSortingRepository: 繼承了CrudRepository

/*
 * Copyright 2008-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

/**
 * Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
 * sorting abstraction.
 * 
 * @author Oliver Gierke
 * @see Sort
 * @see Pageable
 * @see Page
 */
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {

    /**
     * Returns all entities sorted by the given options.
     * 
     * @param sort
     * @return all entities sorted by the given options
     */
    Iterable<T> findAll(Sort sort);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     * 
     * @param pageable
     * @return a page of entities
     */
    Page<T> findAll(Pageable pageable);
}
PagingAndSortingRepository
/**
 * 繼承了Repository,缺點只能對所有的數據進行排序或者分頁
 */
@Repository
public interface UserPagingAndSortingReposiroty extends PagingAndSortingRepository<User, Integer> {
}

 

package com.amber;

import com.amber.pojo.User;
import com.amber.repository.UserPagingAndSortingReposiroty;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = JPAApplication.class)
public class UserPagingAndSortingReposirotyTest {

    @Autowired
    UserPagingAndSortingReposiroty userPagingAndSortingReposiroty;

    /**
     * 排序
     */
    @Test
    public void TestSort(){
        //定義排序規則
        Sort.Order order = new Sort.Order(Sort.Direction.DESC, "name");
        Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");
        //Sort
        Sort sort = new Sort(order, order1);
        List<User> users = (List<User>)userPagingAndSortingReposiroty.findAll(sort);
        System.out.println(users);
    }

    /**
     * 分頁Pageable封裝了分頁的參數,當前頁,每一頁顯示的條數,注意當前頁是從0開始的
     */
    @Test
    public void TestPaging(){
        //Pageable是個接口
        Pageable pageable = new PageRequest(0, 10);
        //返回Page對象
        Page<User> uses = userPagingAndSortingReposiroty.findAll(pageable);
        System.out.println(uses.getTotalElements());
        System.out.println(uses.getTotalPages());
        System.out.println(uses.getNumberOfElements());
    }

    /**
     * 分頁 + 排序
     */
    @Test
    public void TestPagingAndSort(){
        //定義排序規則
        Sort.Order order = new Sort.Order(Sort.Direction.DESC, "name");
        Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");
        //Sort
        Sort sort = new Sort(order, order1);
        //Pageable是個接口
        Pageable pageable = new PageRequest(0, 10, sort);
        //返回Page對象
        Page<User> uses = userPagingAndSortingReposiroty.findAll(pageable);
        System.out.println(uses.getTotalElements());
        System.out.println(uses.getTotalPages());
        System.out.println(uses.getNumberOfElements());
    }

}
UserPagingAndSortingReposirotyTest

 

JPARepository: 繼承了PagingAndSortingRepository接口

在開發中常用JPARepository

優點: 對繼承父接口中方法的返回值進行了適配,因為在父類接口中通常都返回迭代器,需要我們自己進行強制類型轉化。而在JpaRepository中,直接返回了List

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.data.jpa.repository;

import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAllById(Iterable<ID> var1);

    <S extends T> List<S> saveAll(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
JpaRepository

JpaSpecificationExecutor: 這個接口單獨存在,沒有繼承以上說的接口

主要提供了多條件查詢的支持,並且可以在查詢中添加分頁和排序。

因為這個接口單獨存在,因此需要配合以上說的接口使用,如:

/**
 * JpaSpecificationExecutor是單獨存在的,需要配合這JpaRepository一起使用
 */
@Repository
public interface UserJpaSpecificationExecutor extends JpaSpecificationExecutor<User>, JpaRepository<User, Integer> {
}

package com.amber;

import com.amber.pojo.User;
import com.amber.repository.UserJpaSpecificationExecutor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = JPAApplication.class)
public class UserJpaSecificationExecutorTest {

    @Autowired
    UserJpaSpecificationExecutor userJpaSpecificationExecutor;

    /**
     * 多條件查詢的另外一種寫法
     */
    @Test
    public void testUser2(){
        //Specification是個接口,封裝了查詢信息
        Specification<User> specification = new Specification<User>() {
            /**
             * Predicate封裝了單個查詢條件
             * @param root 對查詢對象屬性的封裝,比如我們這里是查詢User,因此root可以看成是User
             * @param query CriteriaQuery封裝了查詢中的各部分信息, Select from order
             * @param cb CB查詢條件的構造器
             * @return
             */
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate p1 = cb.equal(root.get("name"), "amber");
                Predicate p2 = cb.equal(root.get("age"), "18");
                return cb.and(p1,p2);
            }
        };
        List<User> users = userJpaSpecificationExecutor.findAll(specification);
        System.out.println(users);
    }

    /**
     * 多條件查詢
     */
    @Test
    public void testUser1(){
        //Specification是個接口,封裝了查詢信息
        Specification<User> specification = new Specification<User>() {
            /**
             * Predicate封裝了單個查詢條件
             * @param root 對查詢對象屬性的封裝,比如我們這里是查詢User,因此root可以看成是User
             * @param query CriteriaQuery封裝了查詢中的各部分信息, Select from order
             * @param cb CB查詢條件的構造器
             * @return
             */
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                Predicate p1 = cb.equal(root.get("name"), "amber");
                Predicate p2 = cb.equal(root.get("age"), "18");
                predicates.add(p1);
                predicates.add(p2);
                Predicate[] predicateArr = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(predicateArr));
            }
        };
        List<User> users = userJpaSpecificationExecutor.findAll(specification);
        System.out.println(users);
    }

    /**
     * 單條件查詢
     */
    @Test
    public void testUser(){
        //Specification是個接口,封裝了查詢信息
        Specification<User> specification = new Specification<User>() {
            /**
             * Predicate封裝了單個查詢條件
             * @param root 對查詢對象屬性的封裝,比如我們這里是查詢User,因此root可以看成是User
             * @param query CriteriaQuery封裝了查詢中的各部分信息, Select from order
             * @param cb CB查詢條件的構造器
             * @return
             */
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                Predicate p1 = cb.equal(root.get("name"), "amber");
                return p1;
            }
        };
        List<User> users = userJpaSpecificationExecutor.findAll(specification);
        System.out.println(users);
    }
}
View Code

總結:

  Spring Data Jpa中一共提供了

  • Repository:
    •   提供了findBy + 屬性方法 
    •   @Query 
      •   HQL: nativeQuery 默認false
      •   SQL: nativeQuery 默認true
        • 更新的時候,需要配合@Modifying使用
  • CurdRepository:
    • 繼承了Repository 主要提供了對數據的增刪改查
  • PagingAndSortRepository:
    • 繼承了CrudRepository 提供了對數據的分頁和排序,缺點是只能對所有的數據進行分頁或者排序,不能做條件判斷
    JpaRepository: 繼承了PagingAndSortRepository
    • 開發中經常使用的接口,主要繼承了PagingAndSortRepository,對返回值類型做了適配
  • JpaSpecificationExecutor
    • 提供多條件查詢


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM