- ORM概述
##ORM思想
主要目的:操作实体类就相当于操作数据库表
建立两个映射关系: - Hibernate与JPA的概述
##Hibernate框架介绍
Hibernate是一个开放源代码的对象关系映射框架,
它对JDBC进行了非常轻量级的对象封装,
它将POJO与数据库表建立映射关系,是一个全自动的ORM框架 - 抽取JPAUtil工具类
- 使用JPA完成 增删改查操作
##保存
SpringDataJpa是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下专门用来进行数据持久化的解决方案
#SpringDataJpa入门
##需求说明
对客户进行CRUD
##搭建SpringDataJpa的开发环境
创建工程导入坐标
配置spring的配置文件
编写实体类(Customer),使用jpa注解配置映射关系
II.编写一个符合SpringDataJpa的dao层接口
###引入SpringDataJpa的坐标">SpringDataJpa的概述
##SpringDataJpa概述
SpringDataJpa是Spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和。他提供了包括增删改查在内的常用功能,且易于扩展,学习并使用SpringDataJpa可以极大提高开发效率
##SpringDataJpa的特性
SpringDataJpa极大简化了数据库访问层代码。
使用了SpringDataJpa,我们的dao层中只需要写接口,就自动具有了增删改查、分页查询等方法
##SpringDataJpa与JPA和hibernate之间的关系
SpringDataJpa是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下专门用来进行数据持久化的解决方案
#SpringDataJpa入门
##需求说明
对客户进行CRUD
##搭建SpringDataJpa的开发环境
创建工程导入坐标
配置spring的配置文件
编写实体类(Customer),使用jpa注解配置映射关系
II.编写一个符合SpringDataJpa的dao层接口
###引入SpringDataJpa的坐标- 使用SpringDataJpa完成需求

1.通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象
2.SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
3.通过hibernate完成数据库的操作(封装jdbc)">SpringDataJpa的运行过程和原理剖析

1.通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象
2.SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
3.通过hibernate完成数据库的操作(封装jdbc)- 复杂查询
##借助接口中定义好的方法完成查询
findOne(id) : 根据Id查询 - Specifications动态查询
##方法列表
ORM概述
##ORM思想
主要目的:操作实体类就相当于操作数据库表
建立两个映射关系:
实体类和表的映射关系
实体类中属性和表中字段的映射关系
不再重点关注sql语句
为什么使用ORM
当实现一个应用程序时(不使用O/R Mapping),我们可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。对象关系映射(Object Relational Mapping,简称ORM),主要实现程序对象到关系数据库数据的映射
##常见的ORM矿建
实现了ORM思想的框架:MyBatis,Hibernate、Jpa
Hibernate与JPA的概述
##Hibernate框架介绍
Hibernate是一个开放源代码的对象关系映射框架,
它对JDBC进行了非常轻量级的对象封装,
它将POJO与数据库表建立映射关系,是一个全自动的ORM框架
JPA规范
jpa规范,实现jpa规范,内部是由接口和抽象类组成
##JPA与Hibernate的关系

JPA的基本操作
案例:客户的相关操作(增删改查)
客户:就是一家公司
客户表:
jpa操作的操作步骤:
1.加载配置文件创建实体管理器工厂
2.根据实体管理器工厂,创建实体管理器
3.创建事务对象,开启事务
4.增删改查操作
5.提交事务
6.释放资源
搭建环境的过程
1.创建maven工程导入坐标
<dependencies><!--c3p0--><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.5</version></dependency><!--Junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--hibernate对Jpa的支持--><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>5.0.7.Final</version></dependency><!--Log日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!--MySQL and MariaDB--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency></dependencies>
2.需要配置Jpa的核心配置文件
位置:配置到类路径下一个叫做MATA-INF的文件夹下
命名:persistence.xml
<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"><!--需要配置persistent-unit节点持久化单元:name:持久化单元名称transaction-type:事务管理的方式JTA:分布式事务管理RESOURCE-LOCAL:本地事务管理--><persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL"><!--JPA的实现方式--><provider>org.hibernate.jpa.HibernatePersistenceProvider</provider><!--可选配置:配置JPA实现方的配置信息--><properties><!--数据库信息用户名,密码,驱动,数据库地址--><property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/><property name="javax.persistence.jdbc.url" value="jdbc:mysql:///springdata"/><property name="javax.persistence.jdbc.user" value="root"/><property name="javax.persistence.jdbc.password" value="ced51515151"/><!--配置JPA实现方(hibernate)的配置信息显示sql : true | false自动创建数据库表 : hibernate.hbm2ddl.autocreate : 程序运行时创建数据库表(如果有表,先删除再创建)update :程序运行时创建数据库表(如果有表,不会创建表)none :不会创建表--><property name="hibernate.show_sql" value="true"/><property name="hibernate.hbm2ddl.auto" value="create"/></properties></persistence-unit></persistence>
3.编写客户的实体类
4.配置实体类和表,类中属性和表中字段的映射关系
package com.cedric.domain;import javax.persistence.*;/*** 客户实体类* 配置映射关系:* 1.实体类和表的映射关系* 2.实体类中的属性和表中字段的映射关系** @Entity : 声明实体类* @Table : 配置实体类和表的映射关系* name : 配置数据库表的名称*/@Entity@Table(name = "cst_customer")public class Customer {/*** @Id : 声明主键的配置* @GeneratedValue:配置主键的生成策略* strategy* GenerationType.IDENTITY:自增,MySQL* * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)* GenerationType.SEQUENCE:序列,Oracle* * 底层数据库必须支持序列* GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增* GenerationType.AUTO : 由程序自动帮助我们选择主键生成策略* @Column:配置属性和字段的映射关系* name:数据库表中的字段名称*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "cust_id")private Long custId; //客户的主键@Column(name = "cust_name")private String custName;//客户姓名@Column(name = "cust_source")private String custSource;//客户来源@Column(name = "cust_level")private String custLevel;//客户级别@Column(name = "cust_industry")private String custIndustry;//客户所属行业@Column(name = "cust_phone")private String custPhone;//客户联系方式@Column(name = "cust_address")private String custAddress;//客户地址// setter and getter// toString}
5.保存客户到数据库中
package com.cedric.test;
import com.cedric.domain.Customer;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaTest {
/**
* 测试Jpa的保存
* 案例:保存一个客户到数据库中
* Jpa的操作步骤
* 1.加载配置文件创建工厂(实体管理类工厂)对象
* 2.通过实体管理类工厂获取实体管理器
* 3.获取事务对象,开启事务
* 4.完成增删改查操作
* 5.提交事务(回滚事务)
* 6.释放资源
*/
@Test
public void testSave(){
//1.加载配置文件创建工厂(实体管理类工厂)对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//2.通过实体管理类工厂获取实体管理器
EntityManager entityManager = factory.createEntityManager();
//3.获取事务对象,开启事务
EntityTransaction transaction = entityManager.getTransaction();//获取事务对象
transaction.begin();//开启事务
//4.完成增删改查操作:保存一个客户到数据库中
Customer customer = new Customer();
customer.setCustName("张三");
customer.setCustIndustry("国防");
customer.setCustAddress("北京");
customer.setCustLevel("SVIP");
customer.setCustPhone("111");
//保存
entityManager.persist(customer);
//5.提交事务(回滚事务)
transaction.commit();
//6.释放资源
entityManager.close();
factory.close();
}
}
ii.完成基本的CRUD案例
persist : 保存
merge : 更新
remove : 删除
find/getReference : 根据id查询
抽取JPAUtil工具类
package com.cedric.utils;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* 解决实体管理器工厂的浪费资源问题和耗时问题
* 通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象
*
* 第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用方法创建一个EntityManager对象
* 第二次访问getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象
*/
public class JpaUtils {
private static EntityManagerFactory factory;
static {
// 1.加载配置文件,创建entityManagerFactory
factory = Persistence.createEntityManagerFactory("myJpa");
}
/**
* 获取EneieyManager对象
*/
public static EntityManager getEntityManager(){
return factory.createEntityManager();
}
}
使用JPA完成 增删改查操作
##保存
@Test
public void testSave(){
//1.加载配置文件创建工厂(实体管理类工厂)对象
//EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//2.通过实体管理类工厂获取实体管理器
//EntityManager entityManager = factory.createEntityManager();
EntityManager entityManager = JpaUtils.getEntityManager();
//3.获取事务对象,开启事务
EntityTransaction transaction = entityManager.getTransaction();//获取事务对象
transaction.begin();//开启事务
//4.完成增删改查操作:保存一个客户到数据库中
Customer customer = new Customer();
customer.setCustName("张三");
customer.setCustIndustry("国防");
customer.setCustAddress("北京");
customer.setCustLevel("SVIP");
customer.setCustPhone("111");
//保存
entityManager.persist(customer);
//5.提交事务(回滚事务)
transaction.commit();
//6.释放资源
entityManager.close();
//factory.close();
}
修改
/**
* 更新客户的操作
* merge(Object)
*/
@Test
public void testUpdate(){
//1.通过工具类获取entityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.增删改查 -- 更新操作
//i.查询客户
Customer customer = entityManager.find(Customer.class, 1l);
//ii.更新客户
customer.setCustIndustry("线上营销");
entityManager.merge(customer);
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
删除
@Test
public void testRemove(){
//1.通过工具类获取entityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.增删改查 -- 删除客户
// i.根据id查询客户
Customer customer = entityManager.find(Customer.class, 1l);
// ii:调用remove方法完成删除操作
entityManager.remove(customer);
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
查询
/**
* 根据id查询用户
* 使用find方法查询:
* 1.查询的对象就是当前客户对象本身
* 2.在调用find方法的时候,就会发送sql语句查询数据库
*
* 立即加载
*/
@Test
public void testFind(){
//1.通过工具类获取entityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.增删改查 -- 根据id查询用户
/**
* find:根据id查询数据
* class:查询数据的结果需要包装的实体类类型的字节码
* id:查询的主键的取值
*/
Customer customer = entityManager.find(Customer.class, 1l);
System.out.println(customer);
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
/**
* 根据id查询客户
* getReference方法
* 1.获取的对象是一个动态代理对象
* 2.调用getReference方法不会立即发送sql语句查询数据库
* * 当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库
* 延迟加载(懒加载 )
* * 得到的是一个动态代理对象
* * 什么时候用,什么时候才会查询
*/
@Test
public void testReference(){
//1.通过工具类获取entityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.增删改查 -- 根据id查询用户
/**
* getReference:根据id查询数据
* class:查询数据的结果需要包装的实体类类型的字节码
* id:查询的主键的取值
*/
Customer customer = entityManager.getReference(Customer.class, 1l);
System.out.println(customer);
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
jpql查询
复杂查询
###查询全部
/**
* 查询全部
* jqpl:from Customer
* sql:SELECT * FROM cst_customer
*/
@Test
public void testFindAll(){
//1.获取entityManager对象
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.查询全部
String jpql = "from Customer";
Query query = entityManager.createQuery(jpql);
// 发送查询,封装结果集
List list = query.getResultList();
for(Object obj : list){
System.out.println(obj);
}
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
排序查询
/**
* 排序查询:倒叙查询所有客户(根据 id倒序)
* sql: SELECT * FROM cst_customer ORDER BY cust_id DESC
* jqpl: from Customer order by custId desc
*
* 进行jpql查询
* 1.创建query对象
* 2.对参数进行赋值
* 3.查询并得到返回结果
*/
@Test
public void testOrders(){
//1.获取entityManager对象
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.查询全部
String jpql = "from Customer order by custId desc";
Query query = entityManager.createQuery(jpql);
// 发送查询,封装结果集
List list = query.getResultList();
for(Object obj : list){
System.out.println(obj);
}
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
查询总数
@Test
public void testCount(){
//1.获取entityManager对象
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.查询全部
//i.根据jpql语句创建查询对象
String jpql = "select count(custId) from Customer";
Query query = entityManager.createQuery(jpql);
//ii.对参数赋值
//iii.发送查询,封装结果集
/**
* getResultList:直接将查询结果封装为list集合
* getSingleResult:得到唯一的结果集
*/
Object singleResult = query.getSingleResult();
System.out.println(singleResult);
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
分页查询
/**
* 分页查询
* sql : select * from cst_customer limit 0 2
* jpql : from Customer
*/
@Test
public void testPaged(){
//1.获取entityManager对象
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.查询全部
//i.根据jpql语句创建查询对象
String jpql = "from Customer";
Query query = entityManager.createQuery(jpql);
//ii.对参数赋值 -- 分页查询
query.setFirstResult(0);
query.setMaxResults(2);
//iii.发送查询,封装结果集
/**
* getResultList:直接将查询结果封装为list集合
* getSingleResult:得到唯一的结果集
*/
List list = query.getResultList();
for (Object obj : list){
System.out.println(obj);
}
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
条件查询
/**
* 条件查询
* 案例:查询客户名称以“腾讯”开头的客户
* sql : SELECT * FROM cst_customer WHERE cust_name LIKE ?
* jpql: FROM Customer WHERE custName like ?
*/
@Test
public void testCondition(){
//1.获取entityManager对象
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.查询全部
//i.根据jpql语句创建查询对象
String jpql = "from Customer where custName like ?";
Query query = entityManager.createQuery(jpql);
//ii.对参数赋值 -- 占位符参数
//第一个参数:占位符的索引位置(从1)开始,第二个参数:取值
query.setParameter(1,"腾讯%");
//iii.发送查询,封装结果集
/**
* getResultList:直接将查询结果封装为list集合
* getSingleResult:得到唯一的结果集
*/
List list = query.getResultList();
for (Object obj : list){
System.out.println(obj);
}
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
SpringDataJpa的概述
##SpringDataJpa概述
SpringDataJpa是Spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和。他提供了包括增删改查在内的常用功能,且易于扩展,学习并使用SpringDataJpa可以极大提高开发效率
##SpringDataJpa的特性
SpringDataJpa极大简化了数据库访问层代码。
使用了SpringDataJpa,我们的dao层中只需要写接口,就自动具有了增删改查、分页查询等方法
##SpringDataJpa与JPA和hibernate之间的关系

SpringDataJpa是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下专门用来进行数据持久化的解决方案
#SpringDataJpa入门
##需求说明
对客户进行CRUD
##搭建SpringDataJpa的开发环境
创建工程导入坐标
配置spring的配置文件
编写实体类(Customer),使用jpa注解配置映射关系
II.编写一个符合SpringDataJpa的dao层接口
###引入SpringDataJpa的坐标
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<hibernate.version>5.0.7.Final</hibernate.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<c3p0.version>0.9.1.2</c3p0.version>
<mysql.version>8.0.26</mysql.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring beg -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring对orm框架的支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring end -->
<!-- hibernate beg -->
<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>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!-- hibernate end -->
<!-- c3p0 beg -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- c3p0 end -->
<!-- log end -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- spring data jpa 的坐标-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- el beg 使用spring data jpa 必须引入 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<!-- el end -->
</dependencies>
整合SpringDataJpa与Spring
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--spring 和 spring data jpa的配置-->
<!-- 1.创建entityManagerFactory对象交给spring容器管理 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--配置扫描的包(实体类所在的包)-->
<property name="packagesToScan" value="com.cedric.domain"/>
<!--jpa的实现方式-->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
</property>
<!--jpa供应商适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--配置是否自动创建数据库表 -->
<property name="generateDdl" value="false" />
<!--指定数据库类型 -->
<property name="database" value="MYSQL" />
<!--数据库方言:支持的特有语法 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<!--是否显示sql -->
<property name="showSql" value="true" />
</bean>
</property>
<!--jpa的方言 : 高级的特性-->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<!--2.创建数据库连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="cedricasdsaca"></property>
<property name="jdbcUrl" value="jdbc:mysql:///springdata"></property>
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
</bean>
<!--3.整合spring Data Jpa-->
<jpa:repositories base-package="com.cedric.dao" transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory">
</jpa:repositories>
<!--4.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!--5.声明式事务-->
<!--6.配置包扫描-->
<context:component-scan base-package="com.cedric"></context:component-scan>
</beans>
使用JPA注解配置映射关系
package com.cedric.domain;
import javax.persistence.*;
/**
* 1.实体类和表的映射关系
* @Entity
* @Table
* 2.类中属性和表中字段的映射关系
* @Id
* @GeneratedValue
* @Column
*/
@Entity
@Table(name = "cst_customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId;
@Column(name = "cust_address")
private String custAddress;
@Column(name = "cust_industry")
private String custIndustry;
@Column(name = "cust_level")
private String custLevel;
@Column(name = "cust_name")
private String custName;
@Column(name = "cust_phone")
private String custPhone;
@Column(name = "cust_source")
private String custSource;
// set and get
// toString
使用SpringDataJpa完成需求
package com.cedric.dao;
import com.cedric.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* 符合SpringData的dao层的接口规范
* JpaRepository<操作的实体类型,实体类中主键的类型>
* * 封装了基本CRUD操作
* JpaSpecificationExecutor<操作的实体类型>
* * 封装了复杂查询(分页)
*/
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
}
package com.cedric.test;
import com.cedric.dao.CustomerDao;
import com.cedric.domain.Customer;
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 java.util.List;
@RunWith(SpringJUnit4ClassRunner.class) //声明spring提供的单元测试
@ContextConfiguration(locations = "classpath:applicationContext.xml") //指定spring容器的配置信息
public class CustomerDaoTest {
@Autowired
private CustomerDao customerDao;
/**
* 根据id查询
*/
@Test
public void testFindOne(){
Customer customer = customerDao.findOne(3l);
System.out.println(customer);
}
/**
* save:保存或更新
* 根据传递的对象是否存在主键id,
* 如果没有id主键属性:保存
* 存在id主键属性,根据id查询数据,更新数据
*/
@Test
public void testSave(){
Customer customer = new Customer();
customer.setCustName("农夫山泉");
customer.setCustLevel("Vip");
customer.setCustIndustry("营销");
customerDao.save(customer);
}
@Test
public void testUpdate(){
Customer customer = new Customer();
customer.setCustId(4l);
customer.setCustName("农夫山泉有点甜");
customerDao.save(customer);
}
@Test
public void testDelete(){
customerDao.delete(5l);
}
/**
* 查询所有
*/
@Test
public void testFindAll(){
List<Customer> list = customerDao.findAll();
for (Customer customer : list){
System.out.println(customer);
}
}
}
小结
SpringDataJpa的运行过程和原理剖析


1.通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象
2.SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
3.通过hibernate完成数据库的操作(封装jdbc)
复杂查询
##借助接口中定义好的方法完成查询
findOne(id) : 根据Id查询
@Test
public void testFindOne(){
Customer customer = customerDao.findOne(3l);
System.out.println(customer);
}
/**
* 测试统计查询:查询客户的总数量
* count:统计总条数
*/
@Test
public void testCount(){
long count = customerDao.count();//查询全部的客户数量
System.out.println(count);
}
/**
* 测试:判断id为4的客户是否存在
* 1.可以查询一下id为4的客户
* 如果值为空,代表不存在在,如果不为空,代表存在
* 2.判断数据库中id为4的客户的数量
* 如果数量为0,代表不存在,如果大于0,代表存在
*/
@Test
public void testExists(){
boolean exists = customerDao.exists(4l);
System.out.println("id为4的客户是否存在:" + exists);
}
/**
* 根据id从数据库中查询
* @Transactional : 保证getOne正常运行
*
* findOne:
* em.find() :立即加载
* getOne:
* em.getReference :延迟加载
* * 返回的是一个客户的动态代理对象
* * 什么时候用,什么时候查询
*/
@Test
@Transactional
public void testGetOne(){
Customer customer = customerDao.getOne(4l);
System.out.println(customer);
}
jpql的查询方式
jpql : jpa query language(jpa查询语言)
特点:语法或关键字和sql语句类似
查询的是类和类中的属性
需要将JPQL语句配置到接口方法上
1.特有的查询:需要在dao接口上配置方法
2.在新添加的方法上,使用注解的形式配置jpql查询语句
3.注解 : @Query
jpql代码实例
/**
* 符合SpringData的dao层的接口规范
* JpaRepository<操作的实体类型,实体类中主键的类型>
* * 封装了基本CRUD操作
* JpaSpecificationExecutor<操作的实体类型>
* * 封装了复杂查询(分页)
*/
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
/**
* 案例:根据客户名称查询客户
*
* jpql:from Customer where custName = ?
*
* 配置jpql语句,使用@Query注解
*/
@Query(value = "from Customer where custName = ?")
Customer findJpql(String custName);
/**
* 案例:根据客户名称和客户id查询客户
* jpql:from Customer where custName = ? and custId = ?
*
* 可以指定占位符参数的位置
* ? 索引的方式,指定此占位的取值来源
*/
@Query(value = "from Customer where custName = ?2 and custId = ?1")
Customer findCustNameAndId(Long id,String name);
/**
* 使用jpql完成更新操作
* 案例:根据id更新客户名称
* 更新4号客户名称,将名称改为”农夫山泉“
* sql:update cst_customer set cust_name = ? where cust_id = ?
* jpql:update Customer set custName=? where custId = ?
*
* @Query : 代表的是进行查询
* * 声明此方法使用了做更新操作
* @Modifying
* * 当前执行的是一个更新操作
*/
@Query(value = "update Customer set custName = ?2 where custId = ?1")
@Modifying
void updateCustomer(long custId,String name);
/**
* 使用sql的形式查询:
* 查询全部的客户
* sql:select * from cst_customer
* Query:配置sql查询
* value : sql语句
* nativeQuery : 查询方式
* true : sql查询
* false : jpql查询
*
* @return
*/
//@Query(value = "select * from cst_customer",nativeQuery = true)
@Query(value = "select * from cst_customer where cust_name like ?1",nativeQuery = true)
List<Object []> findSql(String name);
/**
* 通过方法名称规则查询
* 是对jpql查询更深入的一层封装
* 我们只需要按照SpringDataJpa提供的方法名称规则定义方法,不需要再去配置jpql语句,完成查询
*
* findBy开头:代表查询
* 对象中属性的名称(首字母大写)
* * 含义:根据属性名称进行查询
*
* findByCustName -- 根据客户名称查询
*
* 在springDataJpa的运行阶段
* 会根据方法名进行解析 findBy from xxx(实体类)
* 属性名称 where custName =
* * 默认情况 : 使用等于的方式查询
* 特殊的查询方式
*
* 1. findBy + 属性名称(根据属性名称进行完成匹配的查询)
* 2. findBy + 属性名称 + ”查询方式(Like | is null)“
* findByCustNameLike
* 3.多条件查询
* findBy + 属性名 + ”查询方式" + “多条件的连接符(and | or)” + 属性名 + “查询方式”
*/
Customer findByCustName(String name);
List<Customer> findByCustNameLike(String custName);
//使用客户名称模糊匹配和客户所属行业精准匹配的查询
Customer findByCustNameLikeAndCustIndustry(String name,String custIndustry);
}
package com.cedric.test;
import com.cedric.dao.CustomerDao;
import com.cedric.domain.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class JpqlTest {
@Autowired
private CustomerDao customerDao;
@Test
public void testFindJPQL(){
Customer customer = customerDao.findJpql("京东");
System.out.println(customer);
}
@Test
public void testFindCustNameAndId(){
Customer customer = customerDao.findCustNameAndId(3l,"京东");
System.out.println(customer);
}
/**
* 测试jpql更新操作
* * springDataJpa中使用jpql完成 更新/删除操作
* * 需要手动添加事务的支持
* * 默认会执行结束之后,回滚事务
*
* @Rollback : 设置是否自动回滚
*/
@Test
@Transactional // 添加事务的支持
@Rollback(value = false)
public void testUpdateCustomer(){
customerDao.updateCustomer(4l,"农夫山泉");
}
// 测试sql查询
@Test
public void testFindSql(){
List<Object[]> list = customerDao.findSql("阿里%");
for (Object[] obj : list){
System.out.println(Arrays.toString(obj));
}
}
@Test
public void testNaming(){
Customer customer = customerDao.findByCustName("京东");
System.out.println(customer);
}
// 测试方法命名规则的查询
@Test
public void testByCustNameLike(){
List<Customer> list = customerDao.findByCustNameLike("阿里%");
for (Customer customer : list){
System.out.println(customer);
}
}
@Test
public void testFindByNameLikeAndCustIndustry(){
Customer customer = customerDao.findByCustNameLikeAndCustIndustry("阿里%", "电商");
System.out.println(customer);
}
}
Specifications动态查询
##方法列表
T findOne(Specification<T> var1); //查询单个对象
List<T> findAll(Specification<T> var1);//查询列表
// 查询全部,分页
// pageable:分页参数
// 返回值:分页pageBean(page:是springdataajpa提供的)
Page<T> findAll(Specification<T> var1, Pageable var2);
//查询列表
//Sort:排序参数
List<T> findAll(Specification<T> var1, Sort var2);
long count(Specification<T> var1);//统计查询
Specification : 查询条件
自定义我们自己的Specification实现类
实现
Root:查询的根对象(查询的任何属性都可以从根对象中获取)
CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
CriteriaBuilder:查询的构造器,封装了很多的查询条件
Predicate toPredicate(Root var1, CriteriaQuery<?> var2, CriteriaBuilder var3); //封装查询条件
代码实例
package com.cedric.test;
import com.cedric.dao.CustomerDao;
import com.cedric.domain.Customer;
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.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.criteria.*;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpecTest {
@Autowired
private CustomerDao customerDao;
/**
* 根据条件,查询单个对象
*/
@Test
public void testSpec(){
/**
* 自定义查询条件
* 1.实现Specification接口(提供泛型,查询的对象类型)
* 2.实现toPredicate方法(构造查询条件)
* 3.需要借助方法参数中的两个参数(
* root:获取需要查询的对象属性
* CriteriaBuilder:构造查询条件的内部封装了很多查询条件(模糊匹配,精准匹配)
* )
*
* 案例:根据客户名称查询,查询客户名为京东的客户
* 查询条件
* 1.查询方式
* cb对象
* 2.比较的属性名称
* root对象
*/
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
// 1.获取比较的属性
Path<Object> custName = root.get("custName");
// 2.构造查询条件 : select * from cst_customer where cust_name = '京东'
/**
* 第一个参数:需要比较的属性(path对象)
* 第二个参数:当前需要比较的取值
*/
Predicate predicate = criteriaBuilder.equal(custName, "京东");//进行精准匹配(比较的属性,比较的属性取值)
return predicate;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
/**
* 多条件查询
* 案例:根据客户名(腾讯)和客户所属行业查询(网游)
*/
@Test
public void testSpec1(){
/**
* root:获取属性
* 客户名
* 所属行业
* criteriaBuilder:构造查询
* 1.构造客户名的精准匹配查询
* 2.构造所属行业的精准匹配查询
* 3.将以上两个查询联系起来
*/
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custName = root.get("custName");//客户名
Path<Object> custIndustry = root.get("custIndustry");//所属行业
//构造函数
//1.构造客户名的精准匹配查询
Predicate predicate = criteriaBuilder.equal(custName, "腾讯");// 第一个参数,path(属性),第二个参数,属性的取值
//2.构造所属行业的精准匹配查询
Predicate predicate1 = criteriaBuilder.equal(custIndustry, "网游");
//3.将多个查询条件组合到一起:组合(满足条件一并且满足条件二:与关系,满足条件一或满足条件二即可:或关系)
Predicate and = criteriaBuilder.and(predicate, predicate1);//以与的形式拼接多个查询条件
//criteriaBuilder.or();//以或的形式拼接多个查询条件
return and;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
/**
* 案例:完美根据客户名称的模糊匹配,返回客户列表
* 客户名称以‘阿里’开头
* equal:直接得到path对象(属性),然后进行比较即可
* gt,lt,ge,le,like:得到path对象,根据path指定比较的参数类型,再去进行比较
* 指定参数类型:path.as(类型的字节码对象)
*/
@Test
public void testSpec3(){
//构造查询条件
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//查询属性:用户名
Path<Object> custName = root.get("custName");
//查询方式:模糊匹配
Predicate like = criteriaBuilder.like(custName.as(String.class), "阿里%");
return like;
}
};
/* List<Customer> all = customerDao.findAll(spec);
for(Customer customer : all){
System.out.println(customer);
}*/
//添加排序
//创建排序对象,需要调用构造方法实例化sort对象
//第一个参数:排序的顺序(倒序,正序)
//Sort.Direction.DESC:倒序
//Sort.Direction.ASC:升序
//第二个参数:排序的属性名称
Sort sort = new Sort(Sort.Direction.DESC,"custId");
List<Customer> all = customerDao.findAll(spec, sort);
for(Customer customer : all){
System.out.println(customer);
}
}
/**
* 分页查询
* Specification:查询条件
* Pageable:分页参数
* 分页参数:查询的页码,每页查询的条数
* findAll(Specification,Pageable):带有条件的分页
* findAll(Pageable):没有条件的分页
* 返回:Page(SpringDataJpa为我们封装好的pageBean对象,数据列表,总条数)
*/
@Test
public void testSpec4(){
Specification spec = null;
//PageRequest对象是Pageable接口的实现类
/**
* 创建PageRequest的过程中,需要调用他的构造方法传入两个参数
* 第一个参数:当前查询的页数(从0开始)
* 第二个参数:每页查询的数量
*/
Pageable pageable = new PageRequest(0,2);
// 分页查询
Page<Customer> page = customerDao.findAll(null, pageable);
System.out.println(page.getContent());//得到数据集合列表
System.out.println(page.getTotalElements());//得到总条数
System.out.println(page.getTotalPages());//得到总页数
}
}
####添加
````java
@Autowired
private CustomerDao customerDao;
@Autowired
private LinkManDao linkManDao;
/**
* 保存一个客户,保存一个联系人
*
* 注意:实体类中需要配置关系,否则外键为空
*/
@Test
@Transactional //配置事务
@Rollback(value = false)//不自动回滚
public void testAdd(){
// 创建一个客户,创建一个联系人
Customer customer = new Customer();
customer.setCustName("火狐");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("Jack");
/**
* 配置了客户到联系人的关系
* 从客户的角度:发送两条insert语句,发送一条更新语句更新数据库(更新外键)
* 由于配置了客户到联系人的关系:客户可以对外键进行维护
*/
customer.getLinkMans().add(linkMan);
customerDao.save(customer);
linkManDao.save(linkMan);
}
@Test
@Transactional //配置事务
@Rollback(value = false)//不自动回滚
public void testAdd1(){
// 创建一个客户,创建一个联系人
Customer customer = new Customer();
customer.setCustName("火狐");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("Jack");
/**
* 配置联系人到客户的关系(多对一)
* 只发送了两条insert语句
* 由于配置了联系人到客户的映射关系(多对一)
*/
linkMan.setCustomer(customer);
customerDao.save(customer);
linkManDao.save(linkMan);
}
@Test
@Transactional //配置事务
@Rollback(value = false)//不自动回滚
public void testAdd2(){
// 创建一个客户,创建一个联系人
Customer customer = new Customer();
customer.setCustName("火狐");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("Jack");
linkMan.setCustomer(customer);//由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经对外键赋值)
customer.getLinkMans().add(linkMan);//由于配置了多的一方到一的一方的关联关系(发送一条update语句)
customerDao.save(customer);
linkManDao.save(linkMan);
}
