Spring-data-jpa的使用

一,spring-data-jpa的簡單介紹

SpringData:Spring 的一個子項目。用於簡化數據庫訪問,支持NoSQL 和 關係數據存儲。其主要目標是使數據庫的訪問變得方便快捷。

SpringData的主要模塊(子項目)
在這裏插入圖片描述
Spring Data JPA: 是springData的子項目,致力於減少數據訪問層 (DAO) 的開發量, 開發者唯一要做的就只是聲明持久層的接口,並繼承Repository(或Repository的子接口即可),其他都交給 Spring Data JPA 來幫你完成!

二,spring-data-jpa的快速入門

創建一個maven java項目

在這裏插入圖片描述

導入的依賴:
spring-data-jpa
Hibernate相關依賴
mysql驅動
c3p0連接池
junit測試

pom.xml文件

<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>cn.xiaogui.example</groupId>
  <artifactId>springdatajpa-example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>springdatajpa-example</name>
  <description>spring-data-jpa的簡單使用</description>
  
  
   <!-- 全局屬性配置  -->
  <properties>
	<project.source.encoding>utf-8</project.source.encoding>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <!-- 防止控制輸出臺中文亂碼 -->
     <argLine>-Dfile.encoding=UTF-8</argLine> 
  	<spring-data-jpa.version>1.10.4.RELEASE</spring-data-jpa.version>
  	<hibernate.version>5.0.11.Final</hibernate.version>
  	<junit.version>4.12</junit.version>
  	<mysql.version>5.1.41</mysql.version>
  	<c3p0.version>0.9.1.2</c3p0.version>
  </properties>
  
  
  <dependencies>
  <!-- spring-data-jpa相關依賴 
      (這個依賴自動把一堆spring的東西依賴進來了,所有可以不需要再引入spring的包)-->
  	<dependency>
  		<groupId>org.springframework.data</groupId>
  		<artifactId>spring-data-jpa</artifactId>
  		<version>${spring-data-jpa.version}</version>
  	</dependency>


  	<dependency>
  		<!-- 做測試使用 -->
  		<groupId>junit</groupId>
  		<artifactId>junit</artifactId>
  		<version>${junit.version}</version>
  		<!-- 這個包只在測試使用 -->
  		<scope>test</scope>
  	</dependency>

	<!-- hibernate相關依賴 -->
  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-core</artifactId>
  		<version>${hibernate.version}</version>
  	</dependency>

  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-entitymanager</artifactId>
  		<version>${hibernate.version}</version>
  	</dependency>
  	
  	<!-- mysql驅動 -->
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>${mysql.version}</version>
  	</dependency>
  	<!--c3p0連接池  -->
  	<dependency>
  		<groupId>c3p0</groupId>
  		<artifactId>c3p0</artifactId>
  		<version>${c3p0.version}</version>
  	</dependency>
  </dependencies>
  
  
  <build>
  	<plugins>
  		<plugin>
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-compiler-plugin</artifactId>
  			<version>3.5.1</version>
  			<configuration>
  				<!--源碼1.7  -->
  				<source>1.7</source>
  				<!-- 打包1.7 -->
  				<target>1.7</target>
  				<encoding>UTF-8</encoding>
  			</configuration>
  		</plugin>
  	</plugins>
  </build>
</project>

由於spring-data-jpa依賴了一堆spring相關的依賴,會自動導入spring相關的一些依賴,所以在pom.xml中不需要引入spring相關的依賴

在這裏插入圖片描述

Spring整合springDataJpa,applicationContext.xml配置

1.首先新建db.properties文件,配置數據庫相關的信息

jdbcUrl=jdbc:mysql://localhost:3306/springdatajpa?characterEncoding=utf8
driverClass=com.mysql.jdbc.Driver
user=root
password=root
initialPoolSize=10
maxPoolSize=30

2.創建applicationContext.xml文件,配置內容如下:

2.2配置包掃描,掃描@Service,@Contorller @Repository
2.3加載springdb.properties文件
2.4配置數據源dataSource

2.5配置JPA的EntityManagerFactory,這裏面配置主要包括:
(1)需要配置數據源dataSource
(2)配置包掃描packagesToScan,掃描實體類,找到實體類上有關JPA的註解;
(3)配置持久化提供者persistenceProvider
(4)配置jpa網絡適配器jpaVendorAdapter,這個裏面主要是關於是否自動建表generateDdl,使用的數據庫database數據庫方言databasePlatform,在控制檯上顯示sql語句showSql等配置

2.6配置事務管理器 transactionManager
2.7配置支持註解的事務
2.8配置SpringData這裏包掃描是掃描dao層,掃描那些定義的接口

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <!-- 配置自動掃描的包,掃描@service @controller @Repository註解-->
   	<context:component-scan base-package="cn.xiaogui"/>
    <!-- 1. 配置數據源 -->
    <context:property-placeholder location="classpath:db.properties"/>
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbcUrl}"/>
        <property name="driverClass" value="${driverClass}"/>
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
        <property name="initialPoolSize" value="${initialPoolSize}"/>
        <property name="maxPoolSize" value="${maxPoolSize}"/>
    </bean>
    <!-- 2. 配置 JPA 的 EntityManagerFactory -->
    <bean id="entityManagerFactory"   class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
         <!-- 配置數據源 --> 
        <property name="dataSource" ref="dataSource"/>
         <!-- 配置包掃描,掃描實體 -->
        <property name="packagesToScan" value="cn.xiaogui.entity"/>
        <!-- 配置持久化提供者 -->
        <property name="persistenceProvider">
			<bean class="org.hibernate.ejb.HibernatePersistence" />
		</property>
        <!-- 配置jpa網絡適配器 -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            	<!-- 是否自動建表 -->
            	<property name="generateDdl" value="true" />
            	<!-- 使用的數據庫 -->
				<property name="database" value="MYSQL" />
				<!--數據庫方言  -->
				<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
				<!-- 在控制檯打印sql語句 -->
				<property name="showSql" value="true" />
            </bean>
        </property>
        <!--配置jpa方言  -->
        <property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</property>
    </bean>
    
    <!-- 3. 配置事務管理器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>  
    </bean>
    <!-- 4. 配置支持註解的事務 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <!-- 5. 配置 SpringData,需要加入  jpa 的命名空間 -->
    <!-- base-package: 掃描 Repository Bean 所在的 package -->
    <jpa:repositories base-package="cn.xiaogui.dao" entity-manager-factory-ref="entityManagerFactory" />
</beans>

3.測試整合

3.1先測試spring容器是否整合成功
在cn.xiaogui.test包下,創建ConfigTest測試類,編寫單元測試代碼,主要內容:
通過靜態代碼塊創建ClassPathXmlApplicationContext對象,加載applicationContext.xml文件,啓動spring容器。通過Spring容器獲取dataSource對象,如果成功獲取,並且說明整合成功了。

測試代碼

package cn.xiaogui.test;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.xiaogui.dao.UserRepository;
/**
 * 
 * @author xiaogui
 * 
 *  Spring整合測試
 *
 */
public class ConfigTest {
	
	private static ApplicationContext applicationContext;
	
	static{
		//使用靜態代碼塊,讓程序來加載spring配置文件
		applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
	}
	
	
	 /** 測試spring容器是否實例化了數據源 。如果實例化了,說明Spring容器整合沒問題 */
	    @Test
	    public void testDataSouce() throws SQLException {
	        DataSource dataSouce = (DataSource) applicationContext.getBean("dataSource");
	        System.out.println("數據源:"+ dataSouce);
	        System.out.println("連接:"+ dataSouce.getConnection());
	    }
    
}

輸出結果:
在這裏插入圖片描述

說明spring整合成功

3.2測試spring整合JPA

整合JPA是否成功主要是看entityManagerFactory這個對象是否起作用,這個會起作用就會去掃描cn.xiaogui.entity包下的實體類,測試方法:

  (1)數據庫提前創建出來,使用到的數據庫springdatajpa我已經創建
  (2) 給實體類加上註解,然後開啓Hibernate自動建表功能,啓動Spring容器;

如果數據庫自動建表成功,那就整合成功

實體類相對簡單,只貼入關鍵部分

User類

@Entity   //表明這個一個實體
@Table(name="t_user")  //數據庫中實體對應的表名
public class User {
	@Id    //id主鍵標識符
	@GeneratedValue(strategy=GenerationType.IDENTITY)  //主鍵生成策略,自動增長
	private Integer id;
	@Column    //對應數據表中的字段名,不寫默認與實體類的屬性名一致
	private String username;
	@Column
	private String city;
	
	@OneToMany(mappedBy="users",fetch=FetchType.EAGER)  //一對多,mappedBy:表示放棄主鍵維護,交給多的一方管理,一的一方fetch默認爲FetchType.LAZY懶加載
	private List<Car> cars = new ArrayList<Car>();

Car類

@Entity   //表明這個一個實體
@Table(name="t_car")  //數據庫中實體對應的表名
public class Car {
	@Id  //id主鍵標識符
	@GeneratedValue(strategy=GenerationType.IDENTITY)//主鍵生成策略,自動增長
	@Column //對應數據表中的字段名,不寫默認與實體類的屬性名一致
	private Integer id;
	@Column
	private String carName;
	@Column
	private Double price;
	
	@ManyToOne //多對一
	@JoinColumn(name="user_id") //外鍵在數據表中的字段
	private User users;

再次執行ConfigTest類中的測試代碼,如果數據庫中創建了User和Car兩張數據表,表明整合JPA成功!

在這裏插入圖片描述

4.在dao層聲明接口
在這裏插入圖片描述

在cn.xiaogui.dao包下創建UserRepository接口,並繼承Repository接口或者Repository的子接口,由於Repository是一個空接口,博主選擇繼承Repository的子接口JpaRepository,在這個接口中提供了一些常規CRUD的操作。而JpaRepository的實現類SimpleJpaRepository對這些CRUD的操作進行了具體的實現,所以我們編寫的UserRepository接口可以直接使用這些方法,而不需要進行具體的實現。

JpaRepository定義的規範:
在這裏插入圖片描述

SimpleJpaRepository對JpaRepository的實現

在這裏插入圖片描述

在這裏插入圖片描述

UserRepository接口代碼

package cn.xiaogui.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import cn.xiaogui.entity.User;

public interface UserRepository extends JpaRepository<User, Integer> {
	

}

在cn.xiaogui.test包下創建UserRepositoryTest測試類,通過這個類,我們進行springData的學習。

package cn.xiaogui.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.xiaogui.dao.UserRepository;
import cn.xiaogui.entity.User;
/**
 * 
 * @author xiaogui
 * 
 *  Spring整合測試
 *
 */
public class UserRepositoryTest {
	
	private static ApplicationContext applicationContext;
	
	private static UserRepository userRepository;
	
	static{
		applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");  //使用靜態代碼塊,讓程序來加載spring配置文件
		userRepository = applicationContext.getBean(UserRepository.class);   //通過反射獲取到UserRepository接口對象
	}
	
	/**
	 * 向t_user數據表中添加一條數據,並查詢這條記錄
	 */
	@Test
	public void insertUser() {
		User user = new User();
		user.setUsername("張三");
		user.setCity("北京");
		//向數據表中保存一條數據
		userRepository.save(user);
		
		//通過用戶名,查詢用戶的信息
		user = userRepository.findOne(1);
	    System.out.println(user);
	}
    
}

執行結果如下圖所示,我們dao層接口UserReository接口只繼承了JpaRepository接口,就可以完成數據添加到數據庫,從數據庫中查詢數據操作,這就是SpringData的魅力所在,大大簡化了我們持久層的開發
在這裏插入圖片描述

三,spring-data-jpa原理分析

springData 出現的目的:爲了簡化,統一持久層 各種實現技術API,所以,springData 提供了一套標準的API 和 不同持久層整合技術的實現。

在這裏插入圖片描述

spring-data-commons :一套標準的API

在這裏插入圖片描述

spring-data-jpa:基於整合jpa實現,還對spring-data-commons的一套標準API進行了擴展

在這裏插入圖片描述

畫圖表示上述接口間的繼承關係

在這裏插入圖片描述

對上述接口中的API進行講解,其中Repository是空接口,不作講解

CrudRepository接口API

在這裏插入圖片描述

PagingAndSortingRepository接口API

在這裏插入圖片描述

JpaRepository接口API

在這裏插入圖片描述

JpaSpecificationExecutor接口API(當需要進行帶條件分頁查詢,多條件查詢實體時,Dao層繼承這個接口)

在這裏插入圖片描述

由於SimpleJpaRepository這個類對上述的這些API進行了具體的實現,所以我們dao層接口只要繼承這些接口即可直接使用這些API。

在這裏插入圖片描述

畫圖簡單分析調用方法的執行流程

在這裏插入圖片描述

四、spring data Query使用 實現條件查詢

第一種方式:基於方法命名規則,自動生成JPQL查詢語句

在這裏插入圖片描述

上圖是對方法命名規則的說明

在cn.xiaogui.test包下創建UserRepositoryCriteriaQuery類,完成條件查詢。

案例說明

基於一列的等值查詢 findBy列名 例如:findByUsername(String name)

package cn.xiaogui.test;

import java.util.List;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.xiaogui.dao.UserRepository;
import cn.xiaogui.entity.User;

public class UserRepositoryCriteriaQuery {
	
	private static ApplicationContext applicationContext;
	
	
	private static UserRepository userRepository; //UserRepository接口的代理對象
	
	static{
		//讀取spring配置文件,加載spring容器
		applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		userRepository = applicationContext.getBean(UserRepository.class);
	}
	/**
	 * 基於一列的等值查詢
	 */
	@Test
	public void findByUsername() {
		List<User> list = userRepository.findByUsername("張三");
		
		System.out.println(list);
	}
}

dao層UserRepository接口只需要創建這個方法,不需要進行具體實現

package cn.xiaogui.dao;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import cn.xiaogui.entity.User;

public interface UserRepository extends JpaRepository<User, Integer> {
	
	/**
	 * 基於一列的等值查詢,不需要進行實現
	 * @param string
	 * @return
	 */
	List<User> findByUsername(String string);
	
}

控制檯查詢結果如下:

在這裏插入圖片描述

基於一列的模糊查詢 findBy列名Like 例如:findByUsernameLike(String name)

由於在條件查詢測試類UserRepositoryCriteriaQuery中,加載spring的配置文件,創建UserRepository接口的代理對象代碼相同,以下的代碼不再重複,只粘貼關鍵部分

UserRepositoryCriteriaQuery代碼片段

	@Test
	public void findByUsernameLike() {
		List<User> list = userRepository.findByUsernameLike("%張%");  //注意:傳入參數  %參數%
		System.out.println(list);
	}

UserRepository接口代碼片段,同樣這個方法也不需要具體實現


	/**
	 * 基於一列的模糊查詢
	 * @param string
	 * @return
	 */

	List<User> findByUsernameLike(String string);

控制檯輸出結果
在這裏插入圖片描述

方法命名規則過多,自己可以嘗試,不做過多贅述

第二種方式:不按命名規則我們自定義的查詢方法,可以在dao層接口的執行方法上配置@Query註解,綁定JPQL語句或SQL語句

在UserRepository接口,自定義一個查詢方法,由於沒有按照方法命名規則,直接報錯

在這裏插入圖片描述

可以在方法上配置@Query註解,表明這是一個查詢方法,value綁定的是JPQL語句或SQL語句,這個有nativeQuery參數決定。默認爲false,表示綁定的是JPQL語句,設置爲true,綁定的是SQL語句

/**
	 * 自定義方法,基於兩列的等值查詢
	 * @param city
	 * @param username
	 * @return
	 */
	@Query(value="from User where username = ? and city = ?",nativeQuery=false)
	User queryUsernameAndCity(String city,String username);

UserRepositoryCriteriaQuery代碼片段

/**
	 * 自定義的查詢方法,基於兩列的等值查詢
	 */
	@Test
	public void queryUsernameAndCity() {
		User user = userRepository.queryUsernameAndCity("北京", "張三");
		System.out.println(user);
	}

控制檯輸出結果:
在這裏插入圖片描述

數據表中存在這條記錄,卻沒有查詢出來。檢查UserRepository接口中定義的這個查詢方法,原來傳入的參數與綁定的JPQL語句中的佔位符沒有對應上。

解決方法:
(1) 在佔位符後面添加標註,與傳入的參數進行對應

	/**
	 * 自定義方法,基於兩列的等值查詢
	 * @param city
	 * @param username
	 * @return
	 */
	@Query(value="from User where username = ?2 and city = ?1",nativeQuery=false)
	User queryUsernameAndCity(String city,String username);

(2)在該方法傳入的參數前面配置@param註解,@param中的參數名稱要和value中的 :後面的名字對應

	/**
	 * 自定義方法,基於兩列的等值查詢
	 * @param city
	 * @param username
	 * @return
	 */
	@Query(value="from User where username = :userName and city = :city",nativeQuery=false)  //@param中的參數名稱要和value中的 :後面的名字對應
	User queryUsernameAndCity(@Param("city") String city,@Param("userName") String username);

使用第二種解決方案,再次執行UserRepositoryCriteriaQuery中這個方法,查詢到數據

在這裏插入圖片描述

第三種方式:不按命名規則我們自定義的查詢方法,可以在dao層接口的執行方法上配置@Query註解,將JPQL語句或SQL語句綁定到實體類上

UserRepository接口代碼片段

/**
	 * 自定義方法,基於兩列的等值查詢
	 * @param city
	 * @param username
	 * @return
	 */
	@Query
	User queryUsernameAndCity2(@Param("city")String city, @Param("username")String username);

User實體類代碼片段

@NamedQueries({
	@NamedQuery(name="User.queryUsernameAndCity2", 
			query = "from User where username = :username and city = :city")})
public class User {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	@Column
	private String username;
	@Column
	private String city;

UserRepositoryCriteriaQuery條件查詢測試類調用方法,可以查詢到結果數據

在這裏插入圖片描述

上述三種條件查詢方式,推薦使用第一種方法命名規則查詢,不建議使用第三種,過於繁瑣

五,帶條件的 修改和刪除操作

使用@Query註解,搭配@Modifying註解完成 帶條件的修改,刪除操作

案例說明:根據id修改用戶名

在UserRepository接口代碼片段

	/**
	 * 自定義修改操作,根據id修改用戶名
	 * UPDATE 或 DELETE 操作需要使用事務, 此時需要定義 Service 層. 在 Service 層的方法上添加事務操作. 
     * 默認情況下, SpringData 的每個方法上有事務, 但都是一個只讀事務. 他們不能完成修改操作!
	 */
	@Query(value="update User set username= ?2 where id = ?1") 
	@Modifying //表示更新操作(修改或刪除)
	void updateUsername(Integer id,String username);

由於修改和刪除都是更新操作,只讀事務是不能實現的,因此新建UserService類,在Service方法中添加事務註解

UserService代碼片段

package cn.xiaogui.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.xiaogui.dao.UserRepository;

@Service
public class UserService {
	@Autowired
	private UserRepository userRepository; //注入dao層接口對象
	
	/**
	 * 根據id修改用戶名
	 */
	public void updateUsername() {
		userRepository.updateUsername(1, "小鬼");
	}
}

在UserRepositoryCriteriaUpdate測試類中調用UserService中的這個方法測試

package cn.xiaogui.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.xiaogui.service.UserService;

public class UserRepositoryCriteriaUpdate {
	
	private static ApplicationContext applicationContext;
	
	private static UserService userService;
	
	static{
		//讀取spring配置文件,加載spring容器
		applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		userService = applicationContext.getBean(UserService.class);
	}
	
	/**
	 * 根據id修改用戶名
	 */
	
	@Test
	public void updateUsername() {
		userService.updateUsername();
	}
	
	
}

控制檯輸出

在這裏插入圖片描述

根據控制檯報出的錯誤,我們需要在UserService中設置事物

/**
	 * 根據id修改用戶名
	 */
	@Transactional
	public void updateUsername() {
		userRepository.updateUsername(1, "小鬼");
	}

再次在UserRepositoryCriteriaUpdate測試類中調用UserService中的這個方法測試,數據修改成功

在這裏插入圖片描述

查詢數據表
在這裏插入圖片描述

刪除操作不再贅述,大家可以自己進行嘗試!

六,帶條件的分頁查詢

首先在數據表t_user中添加數據

在這裏插入圖片描述

實現帶條件的分頁查詢,主要使用到前面提到的JpaSpecificationExecutor接口中定義的API,這個接口的主要作用就是進行帶條件的查詢

在這裏插入圖片描述
進行帶條件的分頁查詢,使用的API是這個接口中的
Page findAll(Specification spec, Pageable pageable);

參數:
spec:構造Specification對象條件查詢對象(類似hibernate的QBC查詢),由於這個參數是一個接口對象,通過匿名對象創建

pageable:封裝了請求分頁的信息: page,size,sort三個參數,其中page索引從0開始,表示第一頁

在這裏插入圖片描述

PageRequest類實現了Pageable接口

由於JpaSpecificationExecutor接口不屬於Repository體系,所以我們要使用帶條件的分頁查詢,dao層接口需要同時繼承JpaRepository,JpaSpecificationExecutor這兩個接口

在這裏插入圖片描述

在UserRepositoryCriteriaQuery測試類中編寫帶條件的分頁查詢代碼

   /**
	 * 實現帶條件的分頁查詢
	 */
	@Test
	public void  findPageData() {
		
		 // 目標:查詢id<5 並且city爲北京的 的第1頁的數據,每頁顯示爲5條記錄
		
		//創建pageable對象  
		Pageable pageable = new PageRequest(1-1, 5);  //0 表示從第一頁開始  5 表示每頁顯示多少條數據
		
		//根據查詢條件,構造Specification對象條件查詢對象(類似hibernate的QBC查詢)
		Specification<User> spec = new Specification<User>() {
			
			/**
			 * 構造條件查詢方法,如果返回值爲null,表示無條件查詢,查詢所有
			 * 
			 * root參數:代表查詢的實體類,用來 獲取條件表達式  username = ? city =? 等
			 * query參數:可以從中可到 Root 對象, 即告知 JPA Criteria 查詢要查詢哪一個實體類. 還可以
			 * 來添加查詢條件, 還可以結合 EntityManager 對象得到最終查詢的 TypedQuery 對象 
			 * cb參數:構造Predicate對象 條件對象,構造複雜查詢效果
			 * @return: Predicate 類型, 代表一個查詢條件. 
			 */
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				//在開發過程中,一般使用root和cb這兩個參數
				
				
				//定義一個list集合,用於存放多個條件
				List<Predicate> predicates = new ArrayList<Predicate>();
				
				//查詢id小於5的數據
				Predicate p1 = cb.lt(root.get("id").as(Integer.class), 5);
				
				predicates.add(p1);
				
				Predicate p2 = cb.equal(root.get("city"), "北京");
				
				predicates.add(p2);
				
				//當predicates中沒有元素時,表示無條件查詢
				return cb.and(predicates.toArray(new Predicate[predicates.size()]));
			}
		};
		//得到分頁對象
		Page<User> page = userRepository.findAll(spec , pageable);
		
		//輸出查詢到的結果
		System.out.println(page.getContent());
	}

在控制檯輸出結果

在這裏插入圖片描述

小結:
主要對springdatajpa的常用操作進行了簡單的說明介紹。

1.如何使用springdata自帶的API及springdatajpa自身擴展的API

2.根據方法命名規則進行條件查詢,以及通過@query註解,進行自定義方法進行條件查詢

3.使用@query ,@modifying註解完成修改或刪除的更新操作

4.最後使用JpaSpecificationExecutor接口中的Page findAll(Specification spec, Pageable pageable)方法,完成帶條件的分頁查詢

分享示例項目在碼雲上的地址:https://gitee.com/xiaoguixiaogege/springdatajpa

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章