Spring Data整合JPA详细过程步骤及方法使用

目录

1.spring data介绍 

2.spring data整合jpa 入门示例(重点) 

3.spring data jpa的接口继承关系 

4.各接口功能使用(重点:JpaRepository) 


 

一、spring Data简介

1.1 spring Data

SpringData:Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。

SpringData 项目所支持 NoSQL 存储: 

--MongoDB (文档数据库) 

--Redis(键/值存储) 

--Hbase(列族数据库) 

SpringData 项目所支持的关系数据存储技术: 

--JPA 

--JDBC

......

致力于减少数据访问层(DAO)的开发量. 开发者唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data来帮你完成!

1.2 JPA(回顾)

JPA(Java Persistence API)是 Sun 官方提出的 ORM标准。 

JPA 是一套规范,不是一套产品,像 Hibernate、TopLink、OpenJPA 它们是一套产品,如果说这些产品实现了这个 JPA 规范,那么就可以叫它们为 JPA 的实现产品

 

1.3 Spring Data JPA

Spring 基于 ORM 框架、JPA 规范的基础上封装的整合 JPA应用框架技术,可使开发者用极简的代码即可实现对数据的访问和操作。

 Spring Data JPA 的技术特点:我们只需要定义接口并继承 Spring Data JPA 中所提供的接口就可以了。不需要编写接口实现类。

 

 

二、Spring Data JPA配置流程

Spring Data JPA如何实现DAO层零实现?

 

Spring Data整合JPA详细过程步骤及方法使用_第1张图片

 

 

三、spring Data JPA入门示例 

3.1配置步骤说明

A. 导入jar包

B. 配置spring-data.xml文件 将spring data jpa与spring整合

C. 创建一个实体类,并配置JPA映射注解

D. 创建一个dao接口,继承JPARepository

E. 创建一个service接口和其实现类,在service实现类注入dao,并编写插入方法

F. 创建测试类,测试serivce插入方法

 

3.2 示例步骤

需求:编写一个Spring Data JPA的项目,插入一条数据到学生信息表

3.2.1 搭建环境

--创建Maven项目并导入包

Spring Data整合JPA详细过程步骤及方法使用_第2张图片

 

--pom.xml依赖配置

  Version>4.0.0

  Id>com

  actId>springData-demo01-start

  on>0.0.1-SNAPSHOT

  

  >

   ins>

   in>- 编译插件 -->

   pId>org.apache.maven.plugins

   factId>maven-compiler-plugin

   ion>3.8.0

   iguration>

   ce>1.8

   et>1.8

   figuration>

   gin>

   gins>

  d>

  dencies>

  

    upId>org.springframework.data

    ifactId>spring-data-jpa

    sion>1.11.0.RELEASE

   pId>org.springframework

   factId>spring-test

   ion>4.3.6.RELEASE

   endency>

   ndency>

   pId>org.hibernate

   factId>hibernate-entitymanager

   ion>5.0.7.Final

   endency>

   ndency>

   pId>mysql

   factId>mysql-connector-java

   ion>5.1.35

   endency>

  

   pId>com.alibaba

   factId>druid

   ion>1.1.9

   endency>

    

roperty name="minIdle" value="${mysql.minIdle}">

roperty name="maxActive" value="${mysql.maxActive}">

bean>

-- 配置JPA EntityManagerFactory -->

ean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

roperty name="dataSource" ref="dataSource">

roperty name="jpaVendorAdapter">--JPA适配器 指定JPA具体实现提供者 -->

ean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

property>

roperty name="packagesToScan" value="com.entity">

roperty name="jpaProperties">

rops>

rop key="hibernate.show_sql">true

rop key="hibernate.format_sql">true

--正向工程  根据实体类注解映射配置自动生成数据库表结构 updata 不删除原表,如果加入新字段则更新表结构-->

rop key="hibernate.hbm2ddl.auto">updateop>

props>

property>

bean>

--配置 spring data 扫描 repository层的包位置  -->

pa:repositories base-package="com.dao" entity-manager-factory-ref="entityManagerFactoryBean">jpa:repositories>

-- 配置JPA事务管理器 spring data默认查找名为transactionManager的事务bean-->

ean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">

roperty name="entityManagerFactory" ref="entityManagerFactoryBean">

bean>

-- 配置事务注解支持 -->

x:annotation-driven transaction-manager="transactionManager"/>

beans>

 

 

--测试连接

import java.sql.SQLException;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.alibaba.druid.pool.DruidDataSource;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

@Autowired

DruidDataSource dataSource;

/**

 * 测试连接

 * @throws SQLException

 */

@Test

public void testConnection() throws SQLException{

System.out.println(dataSource.getConnection());

}

}

 

注:xsd的配置并没有设置版本号,spring会自动从本jar包中加载对应的版本,可以解决断网等情况无法加载xsd文件问题。

以http://www.springframework.org/schema/context/spring-context.xsd为例,

打开spring-context-4.3.6.RELEASE.jar文件,找到spring.schemas文件

Spring Data整合JPA详细过程步骤及方法使用_第3张图片

文件中有一段代码:

Spring Data整合JPA详细过程步骤及方法使用_第4张图片

没有配置版本号时,默认就是当前版本的xsd文件,而且该文件位置就在jar包的org/springframework/context/config/ 目录

Spring Data整合JPA详细过程步骤及方法使用_第5张图片

Spring很贴心,把旧版本的XSD文件也全放了。这样可以防止升级了Spring版本,而配置文件里用的还是旧版本的XSD文件,然后断网了,应用启动不了

 

3.2.4 创建实体类

package com.entity;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

 

@Entity

@Table(name="tb_student")

public class Student {

 

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="stu_id")

private Long stuId;

@Column(name="stu_name")

private String stuName;

@Column(name="stu_age")

private Integer stuAge;

@Column(name="stu_password")

private String stuPassword;

public Long getStuId() {

return stuId;

}

public void setStuId(Long stuId) {

this.stuId = stuId;

}

public String getStuName() {

return stuName;

}

public void setStuName(String stuName) {

this.stuName = stuName;

}

public Integer getStuAge() {

return stuAge;

}

public void setStuAge(Integer stuAge) {

this.stuAge = stuAge;

}

public String getStuPassword() {

return stuPassword;

}

public void setStuPassword(String stuPassword) {

this.stuPassword = stuPassword;

}

@Override

public String toString() {

return "Student [stuId=" + stuId + ", stuName=" + stuName + ", stuAge=" + stuAge + ", stuPassword="

+ stuPassword + "]";

}

}

 

 

3.2.5  创建dao接口

package com.dao;

 

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

import com.entity.Student;

/**

 * JpaRepository:第一个参数是当前dao接口操作的实体类类型名,第二个参数是该实体类的主键类型

 * @author Administrator

 */

public interface StudentDao extends JpaRepository {

 

}

 

 

3.2.6 编写测试类

import java.sql.SQLException;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.alibaba.druid.pool.DruidDataSource;

import com.dao.StudentDao;

import com.entity.Student;

 

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

 

@Autowired

DruidDataSource dataSource;

@Autowired

StudentDao dao;

/**

 * 测试连接

 * @throws SQLException

 */

@Test

public void testConnection() throws SQLException{

System.out.println(dataSource.getConnection());

}

@Test

public void save(){

Student student = new Student();

student.setStuName("张无忌");

student.setStuAge(18);

student = dao.save(student);//返回保存的对象,同时返回主键值

System.out.println(student);

}

}

 

 

Spring Data Jpa会自动执行插入sql语句

Spring Data整合JPA详细过程步骤及方法使用_第6张图片

四、Spring Data JPA dao零实现底层原理

Spring Data JPA dao零实现是如何做到的?

 

编写测试方法

/**

 * 查看dao类型

 */

@Test

public void testSpringData(){

// org.springframework.data.jpa.repository.support.SimpleJpaRepository@377874b4

System.out.println(dao);//动态代理子类

System.out.println(dao.getClass());//代理对象是基于JDK proxy动态代理方式创建的  class com.sun.proxy.$Proxy28

}

 

执行后观察控制台

 

Spring Data 会自动生成org.springframework.data.jpa.repository.support.SimpleJpaRepository类型的代理对象,该类中实现了save()功能,帮我们实现了插入功能。

 

Spring Data JPA 又是如何创建出该代理对象的?

Spring Data 提供了JpaRepositoryFactory对象,该对象会根据StudentDao接口类型自动创建动态代理对象,但是要求StudentDao接口必须是继承Repository接口的

 

编写测试方法实现

@Autowired

EntityManager em;

/**

 * SpringDataJpa底层实现原理

 */

@Test

public void testDaoImpl(){

JpaRepositoryFactory repositoryFactory = new JpaRepositoryFactory(em);

//getRepository(StudentDao.class):该方法会自动生成接口的动态代理子类型,该子类是SimpleJpaRepository的类型  但有要求,接口必须继承Repository接口

StudentDao studentDao = repositoryFactory.getRepository(StudentDao.class);

System.out.println(studentDao);

}

 

观察控制台

 

五、Spring Data JPA 接口继承结构

Spring Data整合JPA详细过程步骤及方法使用_第7张图片

 

 

 

六、Repository接口(自定义查询操作) 

Repository 接口是 Spring Data JPA 中为我我们提供的所有接口中的顶层接口 Repository 提供了两种查询方式的支持

1)基于方法名称命名规则查询

2)基于@Query 注解查询

 

6.1 方法名称命名规则查询

规则:

1. findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)  

如:findByLastName(String lastName);

2.当有多条件查询时,使用规定的关键词连接各个属性,注意属性与参数个数、顺序一一对应

如: findByLastNameAndFirstName(String lastName,String firstName);

 

Spring Data JPA会自动根据方法名进行解析,生成sql查询语句

Spring Data整合JPA详细过程步骤及方法使用_第8张图片

 

Dao接口代码:

package com.dao;

 

import java.util.List;

import org.springframework.data.repository.Repository;

import com.entity.Student;

 

public interface StudentDao extends Repositorytudent, Long> {

 

Student findByStuName(String name);

 

Listudent> findByStuNameStartingWith(String name);

 

Listudent> findByStuNameLikeAndStuAgeGreaterThan(String name, Integer age);

 

Listudent> findAll();

 

}

 

 

测试类代码:

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

@Autowired

StudentDao dao;

/**

 * 需求:根据学生名查询

 */

@Test

public void test1(){

/*

 *判断相等有三种表示方式:

 *1. 什么都不写默认就是相等判断

 *2.Is关键字

 *3.Equal关键字

 */

Student student = dao.findByStuName("张无忌");

System.out.println(student);

}

/**

 * 需求:根据学生名模糊查询 查询姓张的学生

 * Like关键字 : findByStuNameLike("张%")

 */

@Test

public void test2(){

Listtudent> list = dao.findByStuNameStartingWith("张");

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 需求:查询所有记录

 */

@Test

public void test3(){

Listtudent> list = dao.findAll();

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 多条件查询

 * 需求:查询张姓学生,并且年龄大于28岁

 */

@Test

public void test4(){

Listtudent> list = dao.findByStuNameLikeAndStuAgeGreaterThan("张%",28);

for (Student student : list) {

System.out.println(student);

}

}

}

 

 

 

6.2 基于@Query 注解的查询

6.2.1 通过 JPQL 语句查询

JPQL:通过 Hibernate 的 HQL 演变过来的,JPA的自定义查询语句语法

 

创建接口

package com.dao;

 

import java.util.List;

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

import org.springframework.data.repository.Repository;

import org.springframework.data.repository.query.Param;

import com.entity.Student;

 

public interface StudentDao extends Repositorytudent, Long> {

//自定义jpql查询

@Query("select s from Student s")

Listudent> queryFindAll();

@Query("select s from Student s where s.stuName= :stuName")

Student queryFindByStuName(@Param("stuName")String name);

@Query("select s from Student s where s.stuName like ?1%")

Listudent> queryFindByStudentStartingWith(String name);

@Query("select s from Student s where s.stuName like ?1% and s.stuAge>?2")

Listudent> queryFindByStuNameAndStuAge(String name,Integer age);

 

}

 

 

创建测试类

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

@Autowired

StudentDao dao;

/**

 * 测试Query查询jpql

 */

@Test

public void test5(){

Listtudent> list = dao.queryFindAll();

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 测试Query查询jpql

 */

@Test

public void test6(){

Student student = dao.queryFindByStuName("张三丰");

System.out.println(student);

}

/**

 * 测试Query查询jpql

 */

@Test

public void test7(){

Listtudent> list = dao.queryFindByStudentStartingWith("张");

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 测试Query查询jpql

 */

@Test

public void test8(){

Listtudent> list = dao.queryFindByStuNameAndStuAge("张", 28);

for (Student student : list) {

System.out.println(student);

}

}

}

 

 

6.2.2 通过 SQL 语句查询

Spring Data JPA支持编写原生sql语句查询

 

创建Dao接口

package com..dao;

 

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

import org.springframework.data.repository.Repository;

import com.entity.Student;

 

public interface StudentDao extends Repository {

//自定义sql查询

//nativeQuery默认是false,表示不开启原生sql语句查询  

@Query(value="select * from tb_student where stu_name=?1",nativeQuery=true)

Student querySqlFindByStuName(String name);

}

 

 

创建测试类

 

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

@Autowired

StudentDao dao;

/**

 * 测试Query查询sql

 */

@Test

public void test9(){

Student student = dao.querySqlFindByStuName("张三丰");

System.out.println(student);

}

}

 

 

6.2.3通过@Query 注解完成数据更新

1. 事物通常在service定义,使用@Transactional注解,在service层开启事物;

2. @Query注解自带的事务表示是只读状态,因此@Query定义的接口方法,必须用@Modifying注解修改事务的状态;

3. JPQL不支持Insert语法,因此@Query注解定义的方法不支持Insert事务

 

创建dao接口

package com.dao;

 

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

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

import org.springframework.data.repository.Repository;

import com.entity.Student;

 

public interface StudentDao extends Repository {

//自定义jpql 修改  不支持insert

//根据学生id,修改年龄

@Query("update Student s set s.stuAge=?2 where s.stuId=?1")

@Modifying  //Query注解自带的事务 默认是只读事务,需要修改为非只读事务

int updateByStuIdAndStuAge(Long id,Integer age);

 

}

 

 

创建service接口

package com.service;

 

public interface StudentService {

int updateByStuIdAndStuAge(Long id,Integer age);

}

 

 

创建service接口实现类

package com.service;

 

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

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.dao.StudentDao;

 

@Service

public class StudentServiceImpl implements StudentService{

@Autowired

StudentDao dao ;

 

@Override

@Transactional  //开启事务 支持  

public int updateByStuIdAndStuAge(Long id, Integer age) {

return dao.updateByStuIdAndStuAge(id, age);

}

}

 

 

 

创建测试类

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.service.StudentService;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

@Autowired

StudentDao dao;

@Autowired

StudentService service;

/**

 * 测试QueryDDL

 * 需求根据id更新学生年龄

 */

@Test

public void test10(){

int i = service.updateByStuIdAndStuAge(2L, 71);

System.out.println(i);

}

}

 

 

 

七、CrudRepository接口(基本CURD操作) 

CrudRepository接口继承了Repository接口,定义了基本CRUD方法

 

创建接口

package com.dao;

 

import org.springframework.data.repository.CrudRepository;

import com.entity.Student;

 

public interface StudentDao extends CrudRepository {

}

 

 

创建测试类

import java.util.ArrayList;

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

 

@Autowired

StudentDao dao;

/**

 * 添加单条数据

 * 当前dao的代理子类是SimpleJpaRepository类型

 * 该类中的save方法上有@Transactional注解,有事务存在,不用额外开启

 */

@Test

public void test1(){

Student student = new Student();

student.setStuName("赵敏");

student.setStuAge(19);

student = dao.save(student);

System.out.println(student);

}

/**

 * 批量添加

 */

@Test

public void test2(){

Student student = new Student();

student.setStuName("周芷若");

Student student2 = new Student();

student2.setStuName("灭绝师太");

Listtudent> list = new ArrayList();

list.add(student);

list.add(student2);

list = (List) dao.save(list);

System.out.println(list);

}

/**

 * 根据Id查询一条记录

 */

@Test

public void test3(){

Student student = dao.findOne(2L);

System.out.println(student);

}

/**

 * 查询全部记录

 */

@Test

public void test4(){

Listtudent> list = (List) dao.findAll();

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 根据id删除

 */

@Test

public void test5(){

dao.delete(7L);

}

/**

 * 修改:

 * 通过save()操作,根据对象是否有主键id值来进行判断是添加还是更新操作

 */

@Test

public void test6(){

Student student = dao.findOne(2L);

student.setStuAge(70);

System.out.println("student的主键:"+student.getStuId());

student = dao.save(student);//student的修改操作

System.out.println(student);

}

}

 

 

八、PagingAndSortingRepository(分页和排序) 

PagingAndSortingRepository接口继承了CrudRepository接口,定义了分页和排序的查询方法,但该接口上的分页和排序方法不支持条件查询

 

需求:

1. 查询学生表记录,每页显示3条,查询第2页记录

2. 查询学生表记录,按学生Id倒序排序

3. 查询学生表记录,按年龄升序排序,年龄相同的按姓名升序排序

 

创建接口

package com.dao;

 

import org.springframework.data.repository.PagingAndSortingRepository;

import com.entity.Student;

 

public interface StudentDao extends PagingAndSortingRepository {

 

 

}

 

 

创建测试类

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

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

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.data.domain.Sort.Direction;

import org.springframework.data.domain.Sort.Order;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

 

@Autowired

StudentDao dao;

/**

 * 不带条件分页

 * 需求:查询学生表记录,每页显示3条,查询第2页记录

 */

@Test

public void test1(){

//Pageable:分页接口   PageRequest:分页子实现类   

//new PageRequest(page, size) page:当前页索引,从0开始  size每页显示条数

Pageable pageable = new PageRequest(1, 3);

//Page:spring data 提供的分页对象

Pagetudent> page = dao.findAll(pageable);

System.out.println("总条数:"+page.getTotalElements());

System.out.println("总页数:"+page.getTotalPages());

System.out.println("当前页数据:");

Listtudent> list = page.getContent();

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 排序

 * 需求:按学生id倒序排序

 */

@Test

public void test2(){

/*

 * Sort 对象封装了排序规则和指定的排序字段(以属性方式表示)

 * direction:排序规则        properties:指定用于排序的属性

 * Direction:排序枚举

 */

Sort sort = new Sort(Direction.DESC, "stuId");

Listtudent> list = (Listudent>) dao.findAll(sort);

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 多列排序

 * 需求:按年龄升序排序,年龄相同按姓名升序排序

 */

@Test

public void test3(){

/*

 * Sort 对象封装了排序规则和指定的排序字段(以属性方式表示)

 * direction:排序规则        properties:指定用于排序的属性

 * Direction:排序枚举

 */

Order order = new Order(Direction.ASC,"stuAge");

Order order2 = new Order(Direction.ASC,"stuName");

Sort sort = new Sort(order,order2);

Listtudent> list = (Listudent>) dao.findAll(sort);

for (Student student : list) {

System.out.println(student);

}

}

}

 

 

 

九、JpaRepository接口

JpaRepository 接口是我们开发时使用的最多的接口。其特点

1. 可以帮助我们将其他接口的方法的返回值做适配处理

2. 继承了QueryByExampleExecutor接口,支持动态查询

 

创建接口

package com.dao;

 

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

import com.entity.Student;

/**

 * 继承其他父接口,将返回值类型进行重新适配

 * 继承QueryByExampleExecutor接口,支持动态条件查询

 * @author Administrator

 */

public interface StudentDao extends JpaRepository {

 

}

 

 

创建测试类

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.data.domain.Example;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

 

@Autowired

StudentDao dao;

/**

 * 查询全部数据

 */

@Test

public void test1(){

Listtudent> list = dao.findAll();//不需要再强转,自动封装成List

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 动态条件查询

 */

@Test

public void test2(){

Student student = new Student();

student.setStuPassword("1234");

student.setStuAge(18);

//创建一个动态条件对象   生成的sql条件自动忽略null的属性

Example example = Example.of(student);

Listtudent> list = dao.findAll(example);

for (Student stu : list) {

System.out.println(stu);

}

}

@Test

@Transactional//解决session关闭问题

//SimpleJpaRepository

/**

* org.hibernate.LazyInitializationException: could not initialize proxy - no Session

* 会话关闭,整合spring框架后可以通过openSessionInView实现

*/

public void testSelectOne(){

Student one = dao.getOne(1001);//由于其实现api是getReference,该方法是懒加载的方法,在不使用对象的时候,其实不发送sql语句 getOne方法结束,事务关闭

System.out.println("--------------------------");

System.out.println(dao);

System.out.println(one);

}

}

 

 

动态条件查询的控制台输出

Spring Data整合JPA详细过程步骤及方法使用_第9张图片

 

 

 

十、JpaSpecificationExecutor接口

 

1. JpaSpecificationExecutor接口不属于Repository体系,实现了一组 JPA Criteria查询方法

2.该接口方法支持带条件分页查询

3.需要配合JPA其他接口方法一起使用

 

需求:

1. 查询学生id大于2的记录,并按每页显示2条,显示第2页信息

2. 查找id大于1并且姓张的学生,显示第1页,每页显示2条

 

创建dao层

package com.dao;

 

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

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

import com.entity.Student;

 

/**

 * 带条件分页/排排序

 * JpaSpecificationExecutor不单独使用,需要配合JPA其他接口(Repository或其子接口)一起使用

 * 原因:dao的动态代理子类是SimpleJpaRepository类型,JapRepositoryFactory生成该动态代理子类型

 * 要求dao接口必须继承Repository或其子接口

 * @author Administrator

 */

public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {

 

 

}

 

 

创建service接口

package com.service;

 

import org.springframework.data.domain.Page;

import com.entity.Student;

 

public interface StudentService {

//单条件分页   按id分页查询

Pageudent> findAllBySpecification(int page,int size,Long id);

//多条件分页方式1  按id和名字(模糊)分页查询

Pageudent> findAllByIdAndName(int page,int size,Long id,String name);

//多条件分页方式2  按id和名字(模糊)分页查询

Pageudent> findAllByIdAndName2(int page,int size,Long id,String name);

}

 

 

创建Service实现类

package com.service;

 

import java.util.ArrayList;

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 org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Pageable;

import org.springframework.data.jpa.domain.Specification;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.dao.StudentDao;

import com.entity.Student;

 

@Service

public class StudentServiceImpl implements StudentService{

@Autowired

StudentDao dao ;

@Transactional(readOnly=true)

public Page findAllBySpecification(int page,int size,Long id){

//Specification没提供具体实现类,用匿名内部类方式实现创建

Specificationt> spec = new Specificationudent>() {

@Override

/**

 * @return Predicate: JPA Predicate查询条件对象

 * @param  Rootent> root:根对象  封装了实体对象

 * @Param  query:基本查询,可以获取root对象,并对root的查询条件进行进一步过滤

 * @param  cb:构建查询条件对象

 */

public Predicate toPredicate(Root root,

CriteriaQuery query, CriteriaBuilder cb) {

//从root获取实体的studId属性,封装到Path导航对象

Pathng> path = root.get("stuId");

//构建查询条件对象   stuId>id

Predicate predicate = cb.greaterThan(path, id);

return predicate;

}

};

Pageable pageable = new PageRequest(page-1, size);//创建分页对象

Pageudent> studentPage = dao.findAll(spec, pageable);

return studentPage;

}

@Transactional(readOnly=true)

public Page findAllByIdAndName(int page,int size,Long id,String name){

Specificationt> spec = new Specificationudent>() {

/**

 * @return Predicate: JPA Predicate查询条件对象

 * @param  Rootent> root:根对象  封装了实体对象

 * @Param  query:基本查询,可以获取root对象,并对root的查询条件进行进一步过滤

 * @param  cb:构建查询条件对象

 */

@Override

public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {

return cb.and(cb.greaterThan(root.get("stuId"), id),cb.like(root.get("stuName"),name+"%"));

}

};

Pageable pageable = new PageRequest(page-1, size);

Pageudent> studentPage = dao.findAll(spec, pageable);

return studentPage;

}

@Transactional(readOnly=true)

public Page findAllByIdAndName2(int page,int size,Long id,String name){

Specificationt> spec = new Specificationudent>() {

/**

 * @return Predicate: JPA Predicate查询条件对象

 * @param  Rootent> root:根对象  封装了实体对象

 * @Param  query:基本查询,可以获取root对象,并对root的查询条件进行进一步过滤

 * @param  cb:构建查询条件对象

 */

@Override

public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {

Listedicate> list = new ArrayList();

Predicate p1 = cb.greaterThan(root.get("stuId"), id);//条件一

Predicate p2 = cb.like(root.get("stuName"), name+"%");//条件二

list.add(p1);

list.add(p2);//此时条件之间还没有关系

Predicate[] ary = new Predicate[list.size()];

//拼接and关系

return cb.and(list.toArray(ary));

}

};

Pageable pageable = new PageRequest(page-1, size);

Pageudent> studentPage = dao.findAll(spec, pageable);

return studentPage;

}

}

 

 

创建测试类

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

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

import org.springframework.data.domain.Page;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dao.StudentDao;

import com.entity.Student;

import com.service.StudentService;

 

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:spring-data.xml")

public class TestSpringDataJpa {

 

@Autowired

StudentDao dao;

@Autowired

StudentService service;

/**

 * 带条件分页查询

 * 需求:查找id大于3的数据  显示第2页,每页显示2条

 */

@Test

public void test1(){

Pagetudent> page = service.findAllBySpecification(2, 2, 3L);

Listtudent> list = page.getContent();

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 多条件分页查询

 * 需求:查找id大于1并且姓张的学生,显示第1页,每页显示2条

 */

@Test

public void test2(){

Pagetudent> page = service.findAllByIdAndName(1, 2, 1L, "张");

Listtudent> list = page.getContent();

for (Student student : list) {

System.out.println(student);

}

}

/**

 * 多条件分页查询2

 * 需求:查找id大于1并且姓张的学生,显示第1页,每页显示2条

 */

@Test

public void test3(){

Pagetudent> page = service.findAllByIdAndName2(1, 2, 1L, "张");

Listtudent> list = page.getContent();

for (Student student : list) {

System.out.println(student);

}

}

}

 

 

 

你可能感兴趣的:(Java,java,spring,boot,spring)