1. 程式人生 > >Spring Data Jpa --- 入門

Spring Data Jpa --- 入門

一、概述

Spring Data是Spring下的一個子專案,用於簡化資料庫訪問,並支援雲服務的開源框架。Spring Data支援NoSQL和 關係資料儲存,其主要目標是使得資料庫的訪問變得方便快捷。並支援map-reduce框架和雲端計算資料服務。對於擁有海量資料的專案,可以用Spring Data來簡化專案的開發。 然而針對不同的資料儲存訪問使用相對的類庫來操作訪問。Spring Data中已經為我們提供了很多業務中常用的一些介面和實現類來幫我們快速構建專案,比如分頁、排序、DAO一些常用的操作。 

二、環境搭建

1.1 匯入jar包


1.2 applicationContext.xml配置

<?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.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
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- 配置自動掃描的包 -->
	<context:component-scan base-package="com.test.springdata"></context:component-scan>

	<!-- 1. 配置資料來源 -->
	<context:property-placeholder location="classpath:config.properties"/>

	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driver}" />
		<property name="jdbcUrl" value="${jdbc.url}" />
		<property name="user" value="${jdbc.user}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<!-- 2. 配置 JPA 的 EntityManagerFactory -->
	<bean id="entityManagerFactory" 
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
		</property>
		<property name="packagesToScan" value="com.test.springdata"></property>
		<property name="jpaProperties">
			<props>
				<!-- 二級快取相關 -->
				 
				<!-- <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
				<prop key="net.sf.ehcache.configurationResourceName">ehcache-hibernate.xml</prop> -->
				
				<!-- 生成的資料表的列的對映策略 -->
				<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
				<!-- hibernate 基本屬性 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			</props>
		</property>
	</bean>

	<!-- 3. 配置事務管理器 -->
	<bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory"></property>	
	</bean>

	<!-- 4. 配置支援註解的事務 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

	<!-- 5. 配置 SpringData -->
	<!-- 加入  jpa 的名稱空間 -->
	<!-- base-package: 掃描 Repository Bean 所在的 package -->
	<jpa:repositories base-package="com.test.springdata"
		entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>

</beans>


三、Repository介面

Repository 介面是 Spring Data 的一個核心介面,它不提供任何方法,開發者需要在自己定義的介面中宣告需要的方法。

public interface Repository<T, ID extends Serializable> {}
說明:
  • Repository是一個空介面,即是一個標記介面
  • 若我們定義的介面繼承了Repository,則該介面會被IOC容器識別為一個Repository Bean注入到IOC容器中,只要遵循Spring Data的方法定義規範,就無需寫實現類。
  • 與繼承 Repository 等價的一種方式,就是在持久層介面上使用 @RepositoryDefinition 註解,併為其指定 domainClass
    idClass 屬性。如下兩種方式是完全等價的
@RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)
3.1 Repository的子介面

基礎的 Repository 提供了最基本的資料訪問功能,其幾個子介面則擴充套件了一些功能。它們的繼承關係如下: 

  • Repository: 僅僅是一個標識,表明任何繼承它的均為倉庫介面類
  • CrudRepository: 繼承 Repository,實現了一組 CRUD 相關的方法 
  • PagingAndSortingRepository: 繼承 CrudRepository,實現了一組分頁排序相關的方法 
  • JpaRepository: 繼承 PagingAndSortingRepository,實現一組 JPA 規範相關的方法 

3.2 Spring Data方法定義規範

查詢方法以find | read | get開頭,設計條件查詢時,條件的屬性用條件關鍵字連線,要注意的是:條件屬性以首字母大寫。 

例如:定義一個 Entity 實體類 

class User{ 	
     private String firstName; 
     private String lastName; 
}

使用And條件連線時,應這樣寫: 

findByLastNameAndFirstName(String lastName,String firstName); 

條件的屬性名稱與個數要與引數的位置與個數一一對應 

直接在介面中定義查詢方法,如果是符合規範的,可以不用寫實現,目前支援的關鍵字寫法如下:


三、CrudRepository介面

CrudRepository 介面提供了最基本的對實體類的添刪改查操作 

  • T save(T entity);//儲存單個實體 
  • Iterable<T> save(Iterable<? extends T> entities);//儲存集合        
  • T findOne(ID id);//根據id查詢實體         
  • boolean exists(ID id);//根據id判斷實體是否存在         
  • Iterable<T> findAll();//查詢所有實體,不用或慎用!         
  • long count();//查詢實體數量         
  • void delete(ID id);//根據Id刪除實體         
  • void delete(T entity);//刪除一個實體 
  • void delete(Iterable<? extends T> entities);//刪除一個實體的集合         
  • void deleteAll();//刪除所有實體,不用或慎用! 

四、PagingAndSortingRepository介面

PagingAndSortingRepository介面提供了分頁與排序的功能:

  • Iterable<T> findAll(Sort sort); //排序 
  • Page<T> findAll(Pageable pageable); //分頁查詢(含排序功能) 

五、JpaRepository介面

JpaRepository介面提供了JPA的相關功能: 

  • List<T> findAll(); //查詢所有實體 
  • List<T> findAll(Sort sort); //排序、查詢所有實體 
  • List<T> save(Iterable<? extends T> entities);//儲存集合 
  • void flush();//執行快取與資料庫同步 
  • T saveAndFlush(T entity);//強制執行持久化 
  • void deleteInBatch(Iterable<T> entities);//刪除一個實體集合 

示例程式碼

Person實體類

package com.test.springdata;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Table(name="JPA_PERSONS")
@Entity
public class Person {

	private Integer id;
	private String lastName;

	private String email;
	private Date birth;
	
	private Address address;
	
	private Integer addressId;

	@GeneratedValue
	@Id
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getBirth() {
		return birth;
	}

	public void setBirth(Date birth) {
		this.birth = birth;
	}
	
	@Column(name="ADD_ID")
	public Integer getAddressId() {
		return addressId;
	}

	public void setAddressId(Integer addressId) {
		this.addressId = addressId;
	}

	@JoinColumn(name="ADDRESS_ID")
	@ManyToOne
	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", lastName=" + lastName + ", email="
				+ email + ", brith=" + birth + "]";
	}
}

Address實體類
package com.test.springdata;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Table(name="JPA_ADDRESSES")
@Entity
public class Address {

	private Integer id;
	private String province;
	private String city;

	@GeneratedValue
	@Id
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getProvince() {
		return province;
	}

	public void setProvince(String province) {
		this.province = province;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

}

JpaRepsotory類 --- PersonRepsotory類
package com.test.springdata;

import java.util.Date;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;
import org.springframework.data.repository.query.Param;

/**
 * 1、Repository 是一個空介面,即使一個標記介面
 * 2、若我們定義的介面繼承了Repository,則該介面會被IOC容器識別為一個Repository Bean
 * 納入到IOC容器中,進而可以在該介面中定義滿足一定規範的方法
 * 3、可以通過註解的方式標記Repository介面
 */
/**
 * 方式一:繼承Repository<Person,Integer>介面
 * public interface PersonRepsotory extends Repository<Person,Integer>{
 * */

/**
 * 方式二:註解@RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)
 * 
 */
/**
 * 在Repository子介面中宣告方法 
 * 1、不是隨便宣告的,而需要符合一定的規範 
 * 2、查詢方法以find | read | get開頭
 * 3、涉及條件查詢時,條件的屬性用條件關鍵字連線 
 * 4、要注意的是:條件屬性以首字母大寫
 * 5、支援屬性的級聯查詢,若當前類有符合條件的屬性,則優先使用,而不使用級聯屬性。若需要使用級聯屬性,則屬性之間使用_連線
 *
 */
// @RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)
//public interface PersonRepsotory extends Repository<Person, Integer>{
//public interface PersonRepsotory extends CrudRepository<Person, Integer>{
//public interface PersonRepsotory extends JpaRepository<Person, Integer>,JpaSpecificationExecutor<Person>{

public interface PersonRepsotory extends Repository<Person, Integer>{
	
	// 根據lastName來獲取對應的Person
	Person getByLastName(String lastName);

	// Where lastName like ?% And id < ?
	List<Person> getByLastNameStartingWithAndIdLessThan(String lastName, Integer id);

	// Where lastName like %? And id < ?
	List<Person> getByLastNameEndingWithAndIdLessThan(String lastName, Integer id);
	
	//WHERE email IN (?, ?, ?) OR birth < ?
	List<Person> getByEmailInAndBirthLessThan(List<String> emails, Date birth);

	//WHERE a.id > ?
	List<Person> getByAddress_IdGreaterThan(Integer id);
	
	//查詢 id 值最大的那個 Person
	//使用 @Query 註解可以自定義 JPQL 語句以實現更靈活的查詢
	@Query("SELECT p FROM Person p WHERE p.id = (SELECT max(p2.id) FROM Person p2)")
	Person getMaxIdPerson();
	
	//為 @Query 註解傳遞引數的方式1: 使用佔位符. 
	@Query("SELECT p FROM Person p WHERE p.lastName = ?1 AND p.email = ?2")
	List<Person> testQueryAnnotationParams1(String lastName, String email);
	
	//為 @Query 註解傳遞引數的方式1: 命名引數的方式. 
	@Query("SELECT p FROM Person p WHERE p.lastName = :lastName AND p.email = :email")
	List<Person> testQueryAnnotationParams2(@Param("email") String email, @Param("lastName") String lastName);
	
	//SpringData 允許在佔位符上新增 %%. 
	@Query("SELECT p FROM Person p WHERE p.lastName LIKE %?1% OR p.email LIKE %?2%")
	List<Person> testQueryAnnotationLikeParam(String lastName, String email);
	
	//SpringData 允許在佔位符上新增 %%. 
	@Query("SELECT p FROM Person p WHERE p.lastName LIKE %:lastName% OR p.email LIKE %:email%")
	List<Person> testQueryAnnotationLikeParam2(@Param("email") String email, @Param("lastName") String lastName);
	
	//設定 nativeQuery=true 即可以使用原生的 SQL 查詢
	@Query(value="SELECT count(id) FROM jpa_persons", nativeQuery=true)
	long getTotalCount();
	
	//可以通過自定義的 JPQL 完成 UPDATE 和 DELETE 操作. 注意: JPQL 不支援使用 INSERT
	//在 @Query 註解中編寫 JPQL 語句, 但必須使用 @Modifying 進行修飾. 以通知 SpringData, 這是一個 UPDATE 或 DELETE 操作
	//UPDATE 或 DELETE 操作需要使用事務, 此時需要定義 Service 層. 在 Service 層的方法上新增事務操作. 
	//預設情況下, SpringData 的每個方法上有事務, 但都是一個只讀事務. 他們不能完成修改操作!
	@Modifying
	@Query("UPDATE Person p SET p.email = :email WHERE id = :id")
	void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);
	
}

PersonService類

package com.test.springdata;

import java.util.List;

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

@Service
public class PersonService {

	@Autowired
	private PersonRepsotory personRepsotory;
	
	@Transactional
	public void savePersons(List<Person> persons){
		personRepsotory.save(persons);
	}
	
	@Transactional
	public void updatePersonEmail(String email, Integer id){
		personRepsotory.updatePersonEmail(id, email);
	}
}

Test類
package com.test.springdata.test;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;

import com.test.springdata.Person;
import com.test.springdata.PersonRepsotory;
import com.test.springdata.PersonService;


public class SpringDataTest {

	private ApplicationContext ctx = null;
	private PersonRepsotory personRepsotory = null;
	private PersonService personService;
	
	{
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		personRepsotory = ctx.getBean(PersonRepsotory.class);
		personService = ctx.getBean(PersonService.class);
	}
	
	/*@Test
	public void testCommonCustomRepositoryMethod(){
		ApplicationContext ctx2 = new ClassPathXmlApplicationContext("classpath:com/atguigu/springdata/commonrepositorymethod/applicationContext2.xml");
		AddressRepository addressRepository = ctx2.getBean(AddressRepository.class);
		addressRepository.method();
	}
	
	@Test
	public void testCustomRepositoryMethod(){
		personRepsotory.test();
	}*/
		
	/**
	 * 目標: 實現帶查詢條件的分頁. id > 5 的條件
	 * 
	 * 呼叫 JpaSpecificationExecutor 的 Page<T> findAll(Specification<T> spec, Pageable pageable);
	 * Specification: 封裝了 JPA Criteria 查詢的查詢條件
	 * Pageable: 封裝了請求分頁的資訊: 例如 pageNo, pageSize, Sort
	 */
	/*@Test
	public void testJpaSpecificationExecutor(){
		int pageNo = 3 - 1;
		int pageSize = 5;
		PageRequest pageable = new PageRequest(pageNo, pageSize);
		
		//通常使用 Specification 的匿名內部類
		Specification<Person> specification = new Specification<Person>() {
			*//**
			 * @param *root: 代表查詢的實體類. 
			 * @param query: 可以從中可到 Root 物件, 即告知 JPA Criteria 查詢要查詢哪一個實體類. 還可以
			 * 來新增查詢條件, 還可以結合 EntityManager 物件得到最終查詢的 TypedQuery 物件. 
			 * @param *cb: CriteriaBuilder 物件. 用於建立 Criteria 相關物件的工廠. 當然可以從中獲取到 Predicate 物件
			 * @return: *Predicate 型別, 代表一個查詢條件. 
			 *//*
			@Override
			public Predicate toPredicate(Root<Person> root,
					CriteriaQuery<?> query, CriteriaBuilder cb) {
				Path path = root.get("id");
				Predicate predicate = cb.gt(path, 5);
				return predicate;
			}
		};
		
		Page<Person> page = personRepsotory.findAll(specification, pageable);
		
		System.out.println("總記錄數: " + page.getTotalElements());
		System.out.println("當前第幾頁: " + (page.getNumber() + 1));
		System.out.println("總頁數: " + page.getTotalPages());
		System.out.println("當前頁面的 List: " + page.getContent());
		System.out.println("當前頁面的記錄數: " + page.getNumberOfElements());
	}*/
	
	/*@Test
	public void testJpaRepository(){
		Person person = new Person();
		person.setBirth(new Date());
		person.setEmail("[email protected]");
		person.setLastName("xyz");
		
		Person person2 = personRepsotory.saveAndFlush(person);
		
		System.out.println(person == person2);
	}*/
	
	/*@Test
	public void testPagingAndSortingRespository(){
		//pageNo 從 0 開始. 
		int pageNo = 0;
		int pageSize = 5;
		//Pageable 介面通常使用的其 PageRequest 實現類. 其中封裝了需要分頁的資訊
		//排序相關的. Sort 封裝了排序的資訊
		//Order 是具體針對於某一個屬性進行升序還是降序. 
		Order order1 = new Order(Direction.DESC, "id");
		Order order2 = new Order(Direction.ASC, "email");
		Sort sort = new Sort(order1, order2);
		
		PageRequest pageable = new PageRequest(pageNo, pageSize, sort);
		Page<Person> page = personRepsotory.findAll(pageable);
		
		System.out.println("總記錄數: " + page.getTotalElements());
		System.out.println("當前第幾頁: " + (page.getNumber() + 1));
		System.out.println("總頁數: " + page.getTotalPages());
		System.out.println("當前頁面的 List: " + page.getContent());
		System.out.println("當前頁面的記錄數: " + page.getNumberOfElements());
	}*/
	
	@Test
	public void testCrudReposiory(){
		List<Person> persons = new ArrayList<>();
		
		for(int i = 'a'; i <= 'z'; i++){
			Person person = new Person();
			person.setAddressId(i + 1);
			person.setBirth(new Date());
			person.setEmail((char)i + "" + (char)i + "@atguigu.com");
			person.setLastName((char)i + "" + (char)i);
			
			persons.add(person);
		}
		
		personService.savePersons(persons);
	}
	
	@Test
	public void testModifying(){
//		personRepsotory.updatePersonEmail(1, "[email protected]");
		personService.updatePersonEmail("[email protected]", 1);
	}
	
	@Test
	public void testNativeQuery(){
		long count = personRepsotory.getTotalCount();
		System.out.println(count);
	}
	
	@Test
	public void testQueryAnnotationLikeParam(){
//		List<Person> persons = personRepsotory.testQueryAnnotationLikeParam("%A%", "%bb%");
//		System.out.println(persons.size());
		
//		List<Person> persons = personRepsotory.testQueryAnnotationLikeParam("A", "bb");
//		System.out.println(persons.size());
		
		List<Person> persons = personRepsotory.testQueryAnnotationLikeParam2("bb", "A");
		System.out.println(persons.size());
	}
	
	@Test
	public void testQueryAnnotationParams2(){
		List<Person> persons = personRepsotory.testQueryAnnotationParams2("[email protected]", "AA");
		System.out.println(persons);
	}
	
	@Test
	public void testQueryAnnotationParams1(){
		List<Person> persons = personRepsotory.testQueryAnnotationParams1("AA", "[email protected]");
		System.out.println(persons);
	}
	
	@Test
	public void testQueryAnnotation(){
		Person person = personRepsotory.getMaxIdPerson();
		System.out.println(person);
	}
	
	@Test
	public void testKeyWords2(){
		List<Person> persons = personRepsotory.getByAddress_IdGreaterThan(1);
		System.out.println(persons);
	}
	
	@Test
	public void testKeyWords(){
		List<Person> persons = personRepsotory.getByLastNameStartingWithAndIdLessThan("X", 10);
		System.out.println(persons);
		
		persons = personRepsotory.getByLastNameEndingWithAndIdLessThan("X", 10);
		System.out.println(persons);
		
		persons = personRepsotory.getByEmailInAndBirthLessThan(Arrays.asList("[email protected]", "[email protected]", 
				"[email protected]"), new Date());
		System.out.println(persons.size());
	}
	
	@Test
	public void testHelloWorldSpringData() throws FileNotFoundException, IOException, InstantiationException, IllegalAccessException{
		System.out.println(personRepsotory.getClass().getName());
		
		Person person = personRepsotory.getByLastName("AA");
		System.out.println(person);
	}
	
	@Test
	public void testJpa(){
		
	}
	
	@Test
	public void testDataSource() throws SQLException {
		DataSource dataSource = ctx.getBean(DataSource.class);
		System.out.println(dataSource.getConnection());
	}

}

六、JpaSpecificationExecutor介面

不屬於Repository體系,實現一組 JPA Criteria 查詢相關的方法 


Specification:封裝  JPA Criteria 查詢條件。

通常使用匿名內部類的方式來建立該介面的物件

示例程式碼:

Test程式碼,其他程式碼參考JpaRepository

/**
	 * 目標: 實現帶查詢條件的分頁. id > 5 的條件
	 * 
	 * 呼叫 JpaSpecificationExecutor 的 Page<T> findAll(Specification<T> spec, Pageable pageable);
	 * Specification: 封裝了 JPA Criteria 查詢的查詢條件
	 * Pageable: 封裝了請求分頁的資訊: 例如 pageNo, pageSize, Sort
	 */
	@Test
	public void testJpaSpecificationExecutor(){
		int pageNo = 3 - 1;
		int pageSize = 5;
		PageRequest pageable = new PageRequest(pageNo, pageSize);
		
		//通常使用 Specification 的匿名內部類
		Specification<Person> specification = new Specification<Person>() {
			/**
			 * @param *root: 代表查詢的實體類. 
			 * @param query: 可以從中可到 Root 物件, 即告知 JPA Criteria 查詢要查詢哪一個實體類. 還可以
			 * 來新增查詢條件, 還可以結合 EntityManager 物件得到最終查詢的 TypedQuery 物件. 
			 * @param *cb: CriteriaBuilder 物件. 用於建立 Criteria 相關物件的工廠. 當然可以從中獲取到 Predicate 物件
			 * @return: *Predicate 型別, 代表一個查詢條件. 
			 */
			@Override
			public Predicate toPredicate(Root<Person> root,
					CriteriaQuery<?> query, CriteriaBuilder cb) {
				Path path = root.get("id");
				Predicate predicate = cb.gt(path, 5);
				return predicate;
			}
		};
		
		Page<Person> page = personRepsotory.findAll(specification, pageable);
		
		System.out.println("總記錄數: " + page.getTotalElements());
		System.out.println("當前第幾頁: " + (page.getNumber() + 1));
		System.out.println("總頁數: " + page.getTotalPages());
		System.out.println("當前頁面的 List: " + page.getContent());
		System.out.println("當前頁面的記錄數: " + page.getNumberOfElements());
	}


七、自定義Repository介面

步驟:

  • 定義一個介面: 宣告要新增的, 並自實現的方法
  • 提供該介面的實現類: 類名需在要宣告的 Repository 後新增 Impl, 並實現方法
  • 宣告 Repository 介面, 並繼承 1) 宣告的介面使用。
注意: 預設情況下, Spring Data 會在 base-package 中查詢 "介面名Impl" 作為實現類. 也可以通過repository-impl-postfix 聲明後綴

示例程式碼:

PersonDao介面

package com.test.springdata;

public interface PersonDao {
	
	void test();
	
}

PersonDao實現類
package com.test.springdata;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class PersonRepsotoryImpl implements PersonDao {
	
	@PersistenceContext
	private EntityManager entityManager;
	
	@Override
	public void test() {
		Person person = entityManager.find(Person.class, 11);
		System.out.println("-->" + person);
	}

}

PersonRepository類需要繼承PersonDao介面

Test方法

@Test
	public void testCustomRepositoryMethod(){
		personRepsotory.test();
	}


八、@Query註解

8.1 使用@Query自定義查詢,這種查詢可以宣告在Repository方法中,擺脫像命名查詢那樣的約束,將查詢直接在響應的介面方法中宣告,結構更為清晰,這是Spring data的特有實現。

//為 @Query 註解傳遞引數的方式1: 命名引數的方式. 
	@Query("SELECT p FROM Person p WHERE p.lastName = :lastName AND p.email = :email")
	List<Person> testQueryAnnotationParams2(@Param("email") String email, @Param("lastName") String lastName);

8.2 使用@Query的nativeQuery=true,這樣可以使用原生的SQL查詢
//設定 nativeQuery=true 即可以使用原生的 SQL 查詢
	@Query(value="SELECT count(id) FROM jpa_persons", nativeQuery=true)
	long getTotalCount();

注:詳細內容參考JpaRepository示例程式碼

九、@Modifying註解

在 @Query 註解中編寫 JPQL 語句, 但必須使用 @Modifying 進行修飾. 以通知 SpringData, 這是一個 UPDATE 或 DELETE 操作

//可以通過自定義的 JPQL 完成 UPDATE 和 DELETE 操作. 注意: JPQL 不支援使用 INSERT
	//在 @Query 註解中編寫 JPQL 語句, 但必須使用 @Modifying 進行修飾. 以通知 SpringData, 這是一個 UPDATE 或 DELETE 操作
	//UPDATE 或 DELETE 操作需要使用事務, 此時需要定義 Service 層. 在 Service 層的方法上新增事務操作. 
	//預設情況下, SpringData 的每個方法上有事務, 但都是一個只讀事務. 他們不能完成修改操作!
	@Modifying
	@Query("UPDATE Person p SET p.email = :email WHERE id = :id")
	void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);

注意:在呼叫的地方必須加事務,沒有事務不能正常執行

相關推薦

Spring Data JPA入門

pack 列表 1.0 stat 刪除 erp builder epo del 1. Spring Data JPA是什麽 它是Spring基於ORM框架、JPA規範封裝的一套JPA應用框架,可使開發者用極簡的代碼即可實現對數據的訪問和操作。它提供了包括增刪改查等在內的常

Spring Data JPA入門案例

目錄 1. Spring Data JPA介紹        Spring Data JPA 是 Spring 基於 ORM 框架、JPA 規範的基礎上封裝的一套JPA應用框架,可使開發者用極簡的程式碼即可實現對資料庫的訪問和操作。它提供了

Spring Data Jpa 入門 目錄

《Spring Data JPA從入門到精通》購買地址:第一部分:基礎部分第一章 整體認識JPA1.1 市場上ORM框架比對1.2 JPA的介紹以及哪些開源實現1.3 瞭解Spring Data1.3.1 Spring Data介紹1.3.2 Spring Data的子專案有

Spring Data Jpa --- 入門

一、概述 Spring Data是Spring下的一個子專案,用於簡化資料庫訪問,並支援雲服務的開源框架。Spring Data支援NoSQL和 關係資料儲存,其主要目標是使得資料庫的訪問變得方便快捷。並支援map-reduce框架和雲端計算資料服務。對於擁有海量資料的專案

Spring Data JPA入門及深入

一:Spring Data JPA簡介   Spring Data JPA 是 Spring 基於 ORM 框架、JPA 規範的基礎上封裝的一套JPA應用框架,可使開發者用極簡的程式碼即可實現對資料庫的訪問和操作。它提供了包括增刪改查等在內的常用功能,且易於擴充套件!學習並使用 Spring Data JP

Spring Boot入門第二天:一個基於Spring Boot的Web應用,使用了Spring Data JPA和Freemarker。

per pan let mysq 應用 posit ble host thead 今天打算從數據庫中取數據,並展示到視圖中。不多說,先上圖: 第一步:添加依賴。打開pom.xml文件,添加必要的依賴,完整代碼如下: <?xml version="1.0" enco

spring-data-jpa快速入門(一)——

快速 span ron blank support bubuko body lan -s 一、概述   官網:https://projects.spring.io/spring-data-jpa/   1.什麽是spring-data-jpa   Spring D

spring-data-jpa快速入門(二)——簡單查詢

ref spa data mail domain event cif open 寫實 一、方法名解析   1.引言     回顧HelloWorld項目中的dao接口 public interface GirlRepository extends JpaRepos

Spring Data JPA入門到精通》內容簡介、前言

前言 數據庫 公司 查看 小寫 tps 其實在 實戰 感覺 內容簡介 本書以Spring Boot為技術基礎,從入門到精通,由淺入深地介紹Spring Data JPA的使用。有語法,有實踐,有原理剖析。 本書分為12章,內容包括整體認識JPA、JPA基礎查詢方法、定義查

Spring Data JPA入門到精通》 and《Spring Data JPA 實戰》 張振華.Jack --我的書

《Spring Data JPA從入門到精通》購買地址:本書初衷隨著Java技術和微服務技術逐漸廣泛應用,Spring Cloud、Spring Boot逐漸統一Java的框架江湖。市場上的ORM框架也逐漸被人重視起來。Spring Data逐漸走入Java開發者的視野,被很

SpringBoot入門(三)--資料庫操作&&Spring-data-jpa的使用

一、新增依賴 專案程式碼:https://github.com/ffzhihua/springbootdemo  資料庫框架主要使用了sping-data-jpa <!--spring-data-jpa框架--> <depe

Spring Data Jpa系列教程(一)--------入門

大渣好,我是小小書生,現在開始,我們來學習船新的一門技術,SpringDataJpa,它是一個。。額。。(我百度一下) JPA(Java Persistence API)是Sun官方提出的Java持久化規範。它為Java開發人員提供了一種物件/關聯對映工具來管理Java

Spring Data JPA 實例查詢

customer 數據庫表 查詢方式 記錄 如何 三、認識“實例查詢” 1、概念定義: 上面例子中,是這樣創建“實例”的:Example<Customer> ex = Example.of(customer, matcher);我們看到,Example對象,由custom

Spring Data Jpa緩存介紹

級別 instance osc vid group 進程 config 詳細配置 oca 一級緩存: 會話session、事務級別的,事務退出,緩存就失效了。以id為標識 實體管理器-數據源 操作數據拷貝而非數據源。 二級緩存: 線程級或集群級,以id為標識放到緩存(針

SpringBoot中使用Spring Data Jpa 實現簡單的動態查詢的兩種方法

ppr eat value table 得到 blog .net ride integer 首先謝謝大佬的簡書文章:http://www.jianshu.com/p/45ad65690e33# 這篇文章中講的是spring中使用spring data jpa,使用了xml配

spring boot + spring data jpa

分享 users pac frame 配置文件 .sql lda hash chan Spring Data Repository的核心接口是Repository(好像也沒什麽好驚訝的)。這個接口需要領域類(Domain Class)跟領域類的ID類型作為參數。這個接

spring data jpa 關聯設計

join umt table cto ring pre any collect rate MAP關聯實體 // @ElementCollection @OneToMany(cascade = {CascadeType.ALL})// @JoinColumn

Spring Data JPA 參考指南 中文版

參考 指南 get www. book git pri 地址 blank 附下載地址:https://www.gitbook.com/book/ityouknow/spring-data-jpa-reference-documentation/detailsSpring D

spring data jpa自定義baseRepository

ram clas over 找到 ict app ray 註冊 基於 在一些特殊時候,我們會設計到對Spring Data JPA中的方法進行重新實現,這將會面臨一個問題,如果我們新創建一個實現類。如果這個實現類實現了JpaRepository接口,這樣我們不得不實現該接口

Spring Data JPA動態查詢(多條件and)

ica cat 滿足 from pos true ans let tid entity: @Entity @Table(name = "data_illustration") public class Test { @Id @Gen