Spring Data JPA
Posted 专治八阿哥的孟老师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Data JPA相关的知识,希望对你有一定的参考价值。
1. Spring Data环境搭建
Spring
Data提供了一套统一的基于Spring的数据访问模型,它可以轻松的实现数据库访问,包括各种关系型、非关系型数据库、Map-Reduce框架、云数据服务等。Spring Data 包含多个子项目: • Commons - 提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化
• Hadoop - 基于 Spring 的 Hadoop 作业配置和一个 POJO 编程模型的 MapReduce 作业
• Key-Value - 集成了 Redis 和 Riak ,提供多个常用场景下的简单封装
• Document -集成文档数据库:CouchDB 和 MongoDB 并提供基本的配置映射和资料库支持
• Graph - 集成 Neo4j 提供强大的基于POJO 的编程模型
• Graph Roo AddOn - Roo support for Neo4j
• JDBC Extensions- 支持 Oracle RAD、高级队列和高级数据类型
• JPA - 简化创建 JPA 数据访问层和跨存储的持久层功能
• Mapping - 基于 Grails 的提供对象映射框架,支持不同的数据库
• Examples - 示例程序、文档和图数据库
• Guidance - 高级文档
1.1 创建工程
1.2 添加jar包
在pom.xml中加入如下配置:
<dependencies>
<!--Spring Data JPA依赖包-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.7.RELEASE</version>
</dependency>
<!--使用hibernate作为orm实现-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!--junit依赖包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--mysql依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
</dependencies>
1.3 编写数据库配置文件
在resources目录下创建db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8
jdbc.username=你的用户名
jdbc.password=你的密码
需要注意配置文件的编码要与工程的整体编码一致,建议都设置成utf-8。如果从其它地方复制文件,建议先将内容粘贴到记事本中去除编码格式,再粘贴到工程中。
1.4 编写Spring配置文件
在resources目录下创建spring-config.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:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--通过spring加载properties文件-->
<context:property-placeholder location="classpath:db.properties"
ignore-unresolvable="true"/>
<!--配置数据源,$属性名是从配置文件中读取属性值-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="$jdbc.driver"/>
<property name="url" value="$jdbc.url"/>
<property name="username" value="$jdbc.username"/>
<property name="password" value="$jdbc.password"/>
</bean>
<!--指定实现JPA的适配器-->
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
</bean>
<!--EntityManager与持久化上下文相关的,用于操作实体类的实例对象,对实体类对象进行增删改查-->
<!--EntityManagerFactory用于管理EntityManager,-->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="packagesToScan" value="pojo"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<!-- Jpa 事务配置 -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--jpa扫描包中使用Repository子类,并生成代理对象-->
<jpa:repositories base-package="dao"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
</beans>
1.5 创建实体类
在pojo包下创建实体类Dept.java和Employee.java:
package pojo;
import javax.persistence.*;
import java.sql.Date;
@Entity
@Table(name = "EMPLOYEE")//表名
public class Employee
//必须声明一个主键
@Id
@Column(name = "ID")
//主键生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "NAME")//列名
private String name;
@Column(name = "DEPT_ID")
private Integer deptId;
@Column(name = "JOB")
private String job;
@Column(name = "SALARY")
private Float salary;
@Column(name = "HIRE_DATE")
private Date hireDate;
//getter/setter方法略
package pojo;
import javax.persistence.*;
@Entity
//表名如果与类名一样,可以不写@Table
public class Dept
@Id
@Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column//属性名与列名一样,可以不写@Column的name
private String name;
//getter/setter方法略
1.6 编写DAO层
在dao包下创建DeptRepository接口:
package dao;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import pojo.Dept;
/**
* XxxRepository相当于传统项目中的XxxDAO
* 它不需要定义任何方法,因为CrudRepository中有定义常用增删改查方法
* CrudRepository<要操作的实体类, 主键类型>
*/
public interface DeptRepository extends CrudRepository<Dept, Integer>
Repository的作用相当于从前写的DAO接口,但是Repository接口类中暂时不必添加任何方法,因为父接口CrudRepository中已经定义了基本的增删改查方法。
1.7 测试
@Test
public void testSelectAll()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
/**
* 获取Repository对象,虽然配置文件中没有声明id=deptRepository的bean,
* 但是配置了<jpa:repositories>的base-package,不指定bean的id,
* 默认生成的bead的id是类名首字母小写
*/
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
//findAll()是全查,执行的是select * from 表
Iterable<Dept> depts = repository.findAll();
for (Dept dept : depts)
System.out.println(dept.getName());
执行测试方法,可以看到控制台上输出SQL语句:
Hibernate:
select
dept0_.id as id1_0_,
dept0_.name as name2_0_
from
Dept dept0_代表环境配置成功。
2. 使用JPA操作数据库
SpringData的核心接口是Repository,Repository是一个标记接口(如Spring自动扫描的时候,扫描的都是Repository类型,其子类也可以被捕捉到),所有进行数据操作的接口都可以继承Repository并进行拓展。CrudRepository是Repository的子类,提供了常用的增删改查方法。除此之外还有JpaRepository、MongoRepository等,他们都继承了CrudRepository并进行了拓展。
2.1 CrudRepository
CrudRepository接口中定义了常用的增删改查方法,如:
save(S entity):添加/修改数据
findOne(ID primaryKey):根据主键查询
findAll():查询表中所有数据
count():查询表中有多少条记录 delete(T
entity):删除一条记录
exists(ID primaryKey):判断指定主键的数据是否存在
此外还有一些重载的方法,在此不做介绍。
使用CrudRepository操作数据库,需要创建一个接口并继承CrudRepository。语法如下:
public interface DeptRepository extends CrudRepository<Dept, Integer>
CrudRepository<类名,主键类型> 设定类名后,会根据实体类中的注解,找到与此类对应的表进行操作。
2.1.1 添加和修改数据
@Test
public void testSave()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
Dept dept=new Dept();//新创建一个对象,没有主键
dept.setName("jpa测试");
repository.save(dept);//通过save方法保存数据,执行insert
System.out.println(dept.getId());//添加数据后,会看到主键有值了
控制台输出语句: Hibernate:
insert
into
Dept
(name)
values
(?)
@Test
public void testSaveUpdate()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
Dept dept=new Dept();//新创建一个对象
dept.setId(32);//设置主键(数据库中有对应的数据)
dept.setName("jpa测试1");
repository.save(dept);//通过save方法保存数据,执行update
在给实体类设置了主键且数据库中有对应该主键的数据时,控制台输出如下语句: Hibernate:
select
dept0_.id as id1_0_0_,
dept0_.name as name2_0_0_
from
Dept dept0_
where
dept0_.id=? Hibernate:
update
Dept
set
name=?
where
id=?如果把id设置成一个数据库中不存在的值,那么第二条语句会是insert。
可见当主键有值的时候,会先进行查询,根据查询的结果判断是要insert还是update 使用save方法时,分如下几种情况:
- 实体类没有主键值:执行insert新增数据
- 实体类有主键,且主键值在数据库中存在,执行update修改数据
- 实体类有主键,但主键值在数据库中不存在,执行insert插入数据 save有两个重载的方法,除了传入一个对象以外,还可以传入集合,批量插入数据:
@Test
public void testSaveList()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
Dept dept1=new Dept();//新创建一个对象,没有主键
dept1.setName("jpa测试1");
Dept dept2=new Dept();//新创建一个对象,没有主键
dept2.setName("jpa测试2");
List<Dept> deptList=new ArrayList<>();//创建集合,将新对象放入集合中
deptList.add(dept1);
deptList.add(dept2);
repository.save(deptList);//传入集合,批量插入数据
执行测试方法,会看到控制台输出两条insert。
2.1.2 查询数据
CrudRepository中查询的方法有5个:
findOne(id):根据主键查询一个对象
findAll():查询表中所有数据
findAll(Iterator):传入一个主键的集合,使用in子句查询多条数据
exists(id):根据主键判断该条数据是否存在
count():查询数据库中数据的总条数
@Test
public void testFindOne()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
Dept dept=repository.findOne(30);//根据主键查询数据
System.out.println(dept.getId());
执行的语句如下: Hibernate:
select
dept0_.id as id1_0_0_,
dept0_.name as name2_0_0_
from
Dept dept0_
where
dept0_.id=?
@Test
public void testFindAll()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
List<Integer> ids=new ArrayList<>();//创建一个集合作为查询条件
ids.add(29);
ids.add(30);
ids.add(31);
//根据条件查询数据,会执行in子句
Iterable<Dept> depts = repository.findAll(ids);
for (Dept dept : depts)
System.out.println(dept.getName());
执行的语句:
Hibernate:
select
dept0_.id as id1_0_,
dept0_.name as name2_0_
from
Dept dept0_
where
dept0_.id in (
? , ? , ?
)
@Test
public void testExists()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
//根据主键判断数据是否存在
boolean isExists=repository.exists(30);
System.out.println(isExists);
执行的语句: Hibernate:
select
count(*) as col_0_0_
from
Dept dept0_
where
dept0_.id=? 与findOne方法不同的是exists方法查询的是count。
@Test
public void testCount()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
long count=repository.count();//查询表中一共有多少条数据
System.out.println(count);
执行的语句: Hibernate:
select
count(*) as col_0_0_
from
Dept dept0_
2.1.3 删除数据
CrudRepository删除数据有四个方法:
delete(ID):根据主键删除
delete(T):传入对象删除
delete(Iterator):传入一个集合,数据库中与集合元素对应的数据
deleteAll():删除所有数据
@Test
public void testDelete()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
repository.delete(38);//根据主键删除数据
执行的SQL: Hibernate:
select
dept0_.id as id1_0_0_,
dept0_.name as name2_0_0_
from
Dept dept0_
where
dept0_.id=? Hibernate:
delete
from
Dept
where
id=?可以看到调用delete方法的时候先执行了查询,后执行删除。当查询出该主键对应的数据不存在时,会抛出如下异常:
org.springframework.dao.EmptyResultDataAccessException: No class pojo.Dept entity with id 38 exists!
@Test
public void testDeleteEntity()
ApplicationContext ac =
new ClassPathXmlApplicationContext("classpath:spring-config.xml");
DeptRepository repository = (DeptRepository) ac.getBean("deptRepository");
Dept dept = new Dept();//创建要删除的对象
dept.setId(3.1 Spring Data JPA介绍
本节主要介绍Spring
D
ata
JPA
是什么、Spring
D
ata
JPA
核心接口Repository、核心接口间的继承关系图。
3.1.1 Spring Data JPA介绍
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。
所谓规范即只定义标准规则,不提供实现。而JPA的主要实现有Hibernate、EclipseLink、OpenJPA等。
JPA是一套规范,不是一套产品。Hibernate是一套产品,如果这些产品实现了JPA规范,那么我们可以叫它们为JPA的实现产品。
Spring
D
ata
JPA
是Spring
D
ata的一个子项目,它通过提供基于JPA的Respository,极大地减少了JPA作为数据访问方案的代码量。通过Spring
D
ata
JPA
框架,开发者可以省略
实现持久层业务逻辑的工作,唯一要做的,就只是声明持久层的接口,其
它
都交给
Spring Data JPA
来帮你完成
。
3.1.2 核心接口Repository
Spring
D
ata
JPA
最顶层接口是Repository,该接口是所有Repository类的父类。具体代码如下:
package org.springframework.data.repository;
import java.io.Serializable;
public interface Repository<T, ID extends Serializable> {
}
Repository类下没有任何的接口,只是一个空类。Repository接口的子类有
CrudRepository
、
PagingAndSortingRepository
、
JpaRepository
等。其中
CrudRepository
类提供了基本的增删改查等接口,
PagingAndSortingRepository
类提供了基本的分页和排序等接口,而
JpaRepository
是
CrudRepository
和
PagingAndSortingRepository
的子类,继承了它们的所有接口。所以在真实的项目当中,我们都是通过实现
JpaRepository
或者其子类进行基本的数据库操作。
JpaRepository
具体代码如下:
public interface JpaRepository extends PagingAndSortingRepository<T, ID> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAll(Iterable<ID> var1);
<S extends T> List<S> save(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);
}·
@NoRepositoryBean:使用该注解表明,此接口不是一个Repository Bean。
3.1.3 接口继承关系图
Repository接口间的继承关系如图3-
1
所示。通过该继承图,我们可以清楚知道接口间的集成关系。在项目中,我们一般都是实现Jap
R
epository类,加上自己定义的业务方法,来完成我们的业务开发。
图3-1 Repository接口间集成关系
3.2 集成Spring Data JPA
本节主要介绍如何在Spring
B
oot中集成Spring
D
ata
JPA
,服务层类开发,如何通过Spring
D
ata
JPA
实现基本增删改查功能,以及自定义查询方法等内容。
3.2.1 引入依赖
在Spring
B
oot中集成Spring
D
ata
JPA
,首先需要在pom
.xml
文件中引入所需的依赖,具体代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
在之前的章节中,我们已经在开发工具中安装好Maven
H
elper插件,所以大家可以通过该插件查看目前引入的所有依赖,具体如图3-
2
所示。
图3-2 Maven Helper查看pom依赖包
图3-3 my-spring-boot项目目录
3.2.2 继承JpaRepository
在pom
.xml
文件中引入依赖之后,我们在目录/src/main/java/
com.example.demo.repository
下开发一个Ay
U
ser
R
epository类,如图3-
3
所示,具体代码如下:
/**
* 描述:用户Repository
* @author 阿毅
* @date 2017/10/14.
*/
public interface AyUserRepository extends JpaRepository<AyUser,String>{
}
与此同时,我们需要
A
y
U
ser实体类下添加@
E
ntity和@
I
d注解,具体代码如下:
/**
* 描述:用户表
* @Author 阿毅
* @date 2017/10/8.
*/
"ay_user") (name =
public class AyUser {
//主键
private String id;
//用户名
private String name;
//密码
private String password;
}
@Entity:每个持久化POJO类都是一个实体Bean, 通过在类的定义中使用 @Entity 注解来进行声明。
@Table:声明此对象映射到数据库的数据表。该注释不是必须的,如果没有则系统使用默认值(实体的短类名)。
@Id:指定表的主键。
3.2.3 服务层类实现
我们在my-spring-boot项目下继续开发服务层接口类和实现类:
AyUserService
和
AyUserServiceImpl
类。它们分别存放在目录/
src/main/java/com.example.demo.service
和/
src/main/java/com.example.demo.service.impl
下。具体代码如下所示:
/**
* 描述:用户服务层接口
* @author 阿毅
* @date 2017/10/14
*/
public interface AyUserService {
AyUser findById(String id);
List<AyUser> findAll();
AyUser save(AyUser ayUser);
void delete(String id);
}
接口类
AyUserService
定义了4个接口,
findById
和find
A
ll用来查询单个和所有数据,delete用来删除数据,save同时具备保存和更新数据的功能。接口实现类
AyUserServiceImpl
代码如下:
/**
* 描述:用户服务层实现类
* @author 阿毅
* @date 2017/10/14
*/
public class AyUserServiceImpl implements AyUserService{
private AyUserRepository ayUserRepository;
public AyUser findById(String id){
return ayUserRepository.findById(id).get();
}
public List<AyUser> findAll() {
return ayUserRepository.findAll();
}
public AyUser save(AyUser ayUser) {
return ayUserRepository.save(ayUser);
}
public void delete(String id) {
ayUserRepository.deleteById(id);
}
}
@ Service:Spring Boot会自动扫描到@Component注解的类,并把这些类纳入进Spring容器中管理。也可以用@Component注解,只是@Service注解更能表明该类是服务层类。
@Component:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Repository:持久层组件,用于标注数据访问组件,即DAO组件 。
@Resource:这个注解属于J2EE的,默认安照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行查找。如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。具体代码如下:
@Resource(name = "ayUserRepository")
private AyUserRepository ayUserRepository;
@Autowired:这个注解是属于Spring的,默认按类型装配。默认情况下要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。具体代码如下:
private AyUserRepository ayUserRepository;
3.2.4 增删改查分页简单实现
上一节,我们已经在服务层类AyUserService开发完增删改查方法。这一节,我们将继续在类中添加分页接口,具体代码如下:
/**
* 描述:用户服务层接口
* @author 阿毅
* @date 2017/10/14
*/
public interface AyUserService {
AyUser findById(String id);
List<AyUser> findAll();
AyUser save(AyUser ayUser);
void delete(String id);
//分页
Page<AyUser> findAll(Pageable pageable);
}
Pageable:这是一个分页接口,查询时候我们只需要传入一个 Pageable接口的实现类,指定pageNumber和pageSize即可。pageNumber为第几页,而pageSize为每页大小。
Page:分页查询结果会封装在该类中,Page接口实现Slice接口,通过查看其源码可知。我们通过调用getTotalPages和 getContent等方法,可以方便获得总页数和查询的记录。Page接口和Slice接口源码如下:
public interface Page<T> extends Slice<T> {
int getTotalPages();
long getTotalElements();
<S> Page<S> map(Converter<? super T, ? extends S> var1);
}
public interface Slice<T> extends Iterable<T> {
int getNumber();
int getSize();
int getNumberOfElements();
List<T> getContent();
boolean hasContent();
Sort getSort();
boolean isFirst();
boolean isLast();
boolean hasNext();
boolean hasPrevious();
Pageable nextPageable();
Pageable previousPageable();
<S> Slice<S> map(Converter<? super T, ? extends S> var1);
}
分页方法定义好之后,我们在类AyUserServiceImpl中实现该方法,具体代码如下:
public Page<AyUser> findAll(Pageable pageable) {
return ayUserRepository.findAll(pageable);
}
3.2.5 自定义查询方法
我们除了使用
JpaRepository
接口提供的增删改查分页等方法之外,还可以自定义查询方法。我们在
AyUserRepository
类中添加几个自定义查询方法,
具体代码如下:
/**
* 描述:用户Repository
* @author 阿毅
* @date 2017/10/14.
*/
public interface AyUserRepository extends JpaRepository<AyUser,String>{
/**
* 描述:通过名字相等查询,参数为 name
* 相当于:select u from ay_user u where u.name = ?1
*/
List<AyUser> findByName(String name);
/**
* 描述:通过名字like查询,参数为 name
* 相当于:select u from ay_user u where u.name like ?1
*/
List<AyUser> findByNameLike(String name);
/**
* 描述:通过主键id集合查询,参数为 id集合
* 相当于:select u from ay_user u where id in(?,?,?)
* @param ids
*/
List<AyUser> findByIdIn(Collection<String> ids);
}
在AyUserRepository中,我们自定义了3个查询的方法。从代码可以看出,Spring Data JPA为我们约定了一系列的规范,只要我们按照规范编写代码,Spring Data JPA就会根据代码翻译成相关的SQL语句,进行数据库查询。比如我们可以使用findBy、Like、In等关键字。其中findBy可以用read、readBy、query、queryBy、get、getBy来代替。关于查询关键字的更多内容,大家可以到官网(https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/)查看,里面有详细的内容介绍,这里就不一一列举了。
AyUserRepository类中自定义查询方法开发完成之后,我们分别在类AyUserService和类AyUserServiceImpl中调用它们。
AyUserService继续添加这3个方法,具体代码如下:
List<AyUser> findByName(String name);
List<AyUser> findByNameLike(String name);
List<AyUser> findByIdIn(Collection<String> ids);
AyUserServiceImpl
类添加这3个方法,具体代码如下:
public List<AyUser> findByName(String name){
return ayUserRepository.findByName(name);
}
public List<AyUser> findByNameLike(String name){
return ayUserRepository.findByNameLike(name);
}
public List<AyUser> findByIdIn(Collection<String> ids){
return ayUserRepository.findByIdIn(ids);
}
提示:@Override注解不可去掉哦,它帮助我们校验接口方法是否被误改。
3.3 集成测试
3.3.1 测试用例开发
我们在测试类MySpringBootApplicationTests中添加如下代码:
@Resource
private AyUserService ayUserService;
@Test
public void testRepository(){
//查询所有数据
List<AyUser> userList = ayUserService.findAll();
System.out.println("findAll() :" + userList.size());
//通过name查询数据
List<AyUser> userList2 = ayUserService.findByName("阿毅");
System.out.println("findByName() :" + userList2.size());
Assert.isTrue(userList2.get(0).getName().equals("阿毅"),"data error!");
//通过name模糊查询数据
List<AyUser> userList3 = ayUserService.findByNameLike("%毅%");
System.out.println("findByNameLike() :" + userList3.size());
Assert.isTrue(userList3.get(0).getName().equals("阿毅"),"data error!");
//通过id列表查询数据
List<String> ids = new ArrayList<String>();
ids.add("1");
ids.add("2");
List<AyUser> userList4 = ayUserService.findByIdIn(ids);
System.out.println("findByIdIn() :" + userList4.size());
//分页查询数据
PageRequest pageRequest = new PageRequest(0,10);
Page<AyUser> userList5 = ayUserService.findAll(pageRequest);
System.out.println("page findAll():" + userList5.getTotalPages() + "/" + userList5.getSize());
//新增数据
AyUser ayUser = new AyUser();
ayUser.setId("3");
ayUser.setName("test");
ayUser.setPassword("123");
ayUserService.save(ayUser);
//删除数据
ayUserService.delete("3");
}
Assert:添加Assert断言,在软件开发中是一种常用的调试方式。从理论上来说,通过Assert断言方式可以证明程序的正确性。在现在项目中被广泛使用,这是大家需要掌握的基本知识。Assert提供了很多好用的方法,比如isNull,isTrue等。
3.3.2 测试
通过运行3.3.1节中的单元测试用例,我们可以在控制台看到如下的打印信息:
2 :
1 :
1 :
2 :
page findAll():1/10
通过上面的打印信息,可以看出Spring
B
oot集成Spring
D
ata
JPA
已经成功,同时代码中的所有Assert断言都全部通过,说明增删改查分页以及自定义查询方法都可以正常运行。
以上是关于Spring Data JPA的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot数据库交互之Spring Data JPA
微服务 第六章 springboot 通过Spring-data-jpa 配置Oracle数据源(Spring-data-jpa详细介绍)