<style></style>
SpringData JPA(个人看视频记录的,自己使用,大家参考有不懂可留言)
day1:orm思想和hibernate以及jpa的概述和jpa的基本操作
一.orm思想
I.搭建环境的过程
II.完成基本的crud操作
我以一个保存的方式来讲一下jdbc的操作,
i.定义实体类
x@Data
public class User{
private Long id;
private String username;
private String address;
}
ii.创建数据库表
xxxxxxxxxx
create table_user(
id int auto_increment,
username varchar(255),
address varchar(255)
)
iii.进行传统jdbc操作
-
定义SQL
String sql = "INSERT INTO table_user (username,password) VALUES (?,?)";
-
获取链接
Connection conn = DriverManager.getConnection(username,password,url);
-
获取Preparestatment
PrepareStatment pst = conn.prepareStatment (sql);
-
给占位符赋值
pst.setString(1,user.getUserName);
pst.setString(2,user.getAddress);
-
发送查询
pst.excuteUpdate();
-
问题
代码繁琐
需要给占位符赋值
传统jdbc操作
-
定义SQL
String sql = "INSERT INTO table_user (username,password) VALUES (?,?)";
-
获取链接
Connection conn = DriverManager.getConnection(username,password,url);
-
获取Preparestatment
PrepareStatment pst = conn.prepareStatment (sql);
-
给占位符赋值
pst.setString(1,user.getUserName);
pst.setString(2,user.getAddress);
-
发送查询
pst.excuteUpdate();
-
问题
代码繁琐
需要给占位符赋值
如何解决上述问题呢
将jdbc的操作封装到工具类中可以简化一些操作
采用另一种方式
obj.save(user)
拼接sql语句
String sql = insert into values ;
如何动态拼接呢
我们将user和user表进行某种关系的关联
将属性和字段进行关联
当我们传递user时就拿到了表 就可以拿到要获取的数据
操作
建立两个映射关系
-
建立实体类和表的关系
-
建立实体类中属性和表中字段的关系
好处
不用重点关注s:ql语句
实现了ORM思想的框架:mybatis和hibernate
二.hibernate的概述
I. hibernate的概述
Hibernate是一个开放源代码的对象关系映射框架,
它对JDBC进行了非常轻量级的对象封装,
它将POJO与数据库表建立映射关系,是一个全自动的orm框架,
hibernate可以自动生成SQL语句,自动执行,
使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
三.JPA规范
I. JPA规范
-
jdbc规范
sun公司提供的一套接口,各大数据库厂商去实现
-
jpa规范
sun公司提供的一套接口
hibernate或者toplink等框架进行了实现
jpa不是进行操作的,是规范
而是依赖于hibernate或者toplink等框架进行操作的
我们只需要学会这规范就相当于学会了hibernate或toplink等框架
i.JPA概述
JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。
JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
ii.JPA的优势
1.标准化
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
2.容器级特性的支持
JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
3.简单方便
JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成
4.查询能力
JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
5.高级特性
JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。
iii.JPA与hibernate
JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。
JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。
II.操作JPA(第一个入门案例)
这里用了一个案例进行操作
案例:是客户的相关操作(增删改查)
客户:就是一家公司
jpa操作的步骤
-
加载配置文件创建实体管理器工厂
Persistence:静态方法(根据持久化单元名称创建实体管理器工厂)
createEntityManagerFactory(持久化单元名称)
-
根据实体类工厂,创建实体类管理器
EntityManagerFactory :获取EntiManager对象
方法 createEntityManager
*.内部维护了数据库信息
*.内部维护了缓存信息
*.维护了所有实体类管理器对象
*.再创建EntityManagerFactory的过程中会根据配置创建数据库表
EntityManagerFactory的过程比较浪费资源
特点:线程安全的对象
多个线程访问同一个EntityManagerFactory不会有线程安全问题
如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题
静态代码块的形式创建EntityManagerFactory
-
创建事务对象,开启事务
EntityManager对象 实体类管理器
beginTransaction:创建事务对象
persist保存
merge更新
remove删除
find/getRefrence根据id查询
Transaction 对象 事务
begin 开启事务
commit 提交事务
rollback 回滚
i.搭建环境的过程
i.创建maven工程导入坐标
*.坐标如下
xxxxxxxxxx
<!--引入jpa所需坐标-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.hibernate.version>5.0.7.Final</project.hibernate.version>
</properties>
<dependencies>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- hibernate对jpa的支持包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${project.hibernate.version}</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${project.hibernate.version}</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.20</version>
</dependency>
</dependencies>
ii.需要配置jpa的核心配置文件
*.位置:配置到类路径下的一个叫做META-INF的文件夹下 需自己手动创建
*.命名:persistence.xml
*.xml配置如下
xxxxxxxxxx
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--需要配置persistence-unit节点
持久化单元
name:持久化单元名称
transaction-type:事务管理的方式
JTA: 分布式事务管理
RESOURCE_LOCAL:本地事务管理 (所有表都在一个库中)
-->
<persistence-unit name="myJpaI" transaction-type="RESOURCE_LOCAL">
<!--jpa的实现方式-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--数据库信息
用户名 javax.persistence.jdbc.user
密码 javax.persistence.jdbc.password
驱动 javax.persistence.jdbc.driver
数据库地址 javax.persistence.jdbc.url
-->
<properties>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://127.0.0.1:3306/db_jpa?serverTimezone=GMT%2B8"/>
<!--可选配置,配置jpa实现方言的配置信息 Hibernate
显示SQL true | false 显示 | 不显示
自动创建数据表
create 程序运行时创建数据库表(如果有表,先删除在创建表)
update 程序运行时创建表,如果有表不会创建表
none 不会创建表
-->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl" value="create"/>
</properties>
</persistence-unit>
</persistence>
iii.编写客户的实体类
*.实体类代码如下
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import java.io.Serializable;
/**
* 客户实体类
*/
public class Customer implements Serializable {
private static final long serialVersionUID = -2382852293113450787L;
/**
* 客户编号(主键)
*/
private Long custId;
/**
* 客户名称(公司名称)
*/
private String custName;
/**
* 客户信息来源
*/
private String custSource;
/**
* 客户所属行业
*/
private String custIndustry;
/**
* 客户级别
*/
private String custLevel;
/**
* 客户联系地址
*/
private String custAddress;
/**
* 客户联系电话
*/
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
}
iv,配置实体类和表,类和表中字段的映射关系
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import javax.persistence.*;
import java.io.Serializable;
/**
* 客户实体类
* 配置映射关系
* 1.实体类和表的映射关系
* 2.实体类中属性和表字段的映射关系
* 使用注解
* <p>
* 1.表操作
*
* @Entity javax.persistence.Entity; 配置实体类和表的映射关系
* @Table 配置实体类和表的映射关系
* name: 配置数据库表的名称
* <p>
* 2.字段操作 配置实体类中属性和表中字段的映射关系
* 主键配置
*/
@Entity
@Table(name = "cst_customer")
public class Customer implements Serializable {
private static final long serialVersionUID = -2382852293113450787L;
/**
* 客户编号(主键)
*
* @Id 声明主键的配置
* @GeneratedValue 配置主键的生成策略
* strategy GenerationType.IDENTITY 自增
* @Colunm 配置属性和字段的映射关系
* 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 custIndustry;
/**
* 客户级别
*/
@Column(name = "cust_address")
private String custLevel;
/**
* 客户联系地址
*/
@Column(name = "cust_phone")
private String custAddress;
/**
* 客户联系电话
*/
@Column(name = "cust_id")
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
}
v.保存客户到数据库中
操作代码如下
xxxxxxxxxx
package com.it.fuxinyu.test;
import com.it.fuxinyu.pojo.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("myJpaI");
//2.通过实体管理类工厂获取实体类管理器
EntityManager entityManager = factory.createEntityManager();
//3.获取事务对象并开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//4.创建实体类,完成增删改查
Customer customer = new Customer();
customer.setCustName("赵雅芝2");
customer.setCustAddress("香港");
entityManager.persist(customer);
//5.提交事务
transaction.commit();
//6.释放资源
entityManager.close();
factory.close();
}
}
ii.完成基本的CRUD操作
-
增删改查操作
persist保存
xxxxxxxxxx
/**
* 测试JPA的保存
* JPA的操作步骤
* 1.加载配置文件创建工厂(实体管理类工厂)对象
* 2.通过实体管理类工厂获取实体类管理器
* 3.开启事务 获取事务对象开启事务
* 4.完成增删改查
* 5.提交事务(回滚事务)
* 6.释放资源
*/
@Test
public void testSave() {
//1.加载配置文件创建工厂(实体管理类工厂)对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpaI");
//2.通过实体管理类工厂获取实体类管理器
EntityManager entityManager = factory.createEntityManager();
//3.获取事务对象并开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//4.创建实体类,完成增删改查
Customer customer = new Customer();
customer.setCustName("xxx2");
customer.setCustAddress("aa");
entityManager.persist(customer);
//5.提交事务
transaction.commit();
//6.释放资源
entityManager.close();
factory.close();
}
getRefrence根据id查询
xxxxxxxxxx
/**
* getReference方法
* 1.获取的对象是一个动态代理对象
* 2.调用getReference方法不会立即发送sql语句查询数据库
* 当查询结果对象的时候才会发送sql语句,什么时候用什么时候发送sql语句查询数据库
* 延时加载(懒加载)
* 得到的是一个动态代理的对象
* 什么时候用,什么时候才会查询
*/
@Test
public void testGetReference() {
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//增删改查
Customer customer = entityManager.getReference(Customer.class, Long.valueOf(1));
// System.out.println(customer);
transaction.commit();
entityManager.close();
}
find根据id查询
xxxxxxxxxx
/**
* 根据id查询客户
* 使用find方法的时候,就会发送sql语句查询数据库
* 立即加载
* 只要调用就会执行,是比较浪费效率的
*/
@Test
public void testFind() {
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//增删改查
Customer customer = entityManager.find(Customer.class, Long.valueOf(1));
// System.out.println(customer);
transaction.commit();
entityManager.close();
}
remov根据id进行删除
xxxxxxxxxx
/**
* 删除
*/
@Test
public void testRemove() {
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = entityManager.find(Customer.class, Long.valueOf(2));
entityManager.remove(customer);
transaction.commit();
entityManager.close();
}
merge根据id进行修改
xxxxxxxxxx
/**
* 修改
*/
@Test
public void testUpdate() {
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = entityManager.find(Customer.class, Long.valueOf(3));
customer.setCustName("邵丹做个人吧");
entityManager.merge(customer);
transaction.commit();
entityManager.close();
}
iii.JPQL的基本操作
xxxxxxxxxx
/**
* 查询全部
* jpql:from Customer
* sql: SELECT*FROM cst_customer
*/
@Test
public void testSelectAll() {
String jpql = "from com.it.fuxinyu.pojo.Customer";
//1.获取entityManager对象
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//3.增删改查
Query query = entityManager.createQuery(jpql);
List resultList = query.getResultList();
System.out.println(resultList);
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
xxxxxxxxxx
/**
* 倒序查询所有
* jpql: "from com.it.fuxinyu.pojo.Customer order by custId DESC";
* sql: SELECT*FROM cst_customer order by custId DESC";
*/
@Test
public void testOrders() {
String jpql = "from com.it.fuxinyu.pojo.Customer order by custId DESC";
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Query query = entityManager.createQuery(jpql);
List resultList = query.getResultList();
System.out.println(resultList);
transaction.commit();
entityManager.close();
}
xxxxxxxxxx
/**
* 查询总记录数
* sql:SELECT COUNT(*) FROM cst_customer
* jpql:
*/
@Test
public void testCount() {
String jpql = "SELECT COUNT(custId) FROM com.it.fuxinyu.pojo.Customer";
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Query query = entityManager.createQuery(jpql);
Object singleResult = query.getSingleResult();
System.out.println(singleResult);
transaction.commit();
entityManager.close();
}
xxxxxxxxxx
/**
* 分页查询
* sql:SELECT COUNT(*) FROM cst_customer LIMIT 0,2
* jpql: "FROM com.it.fuxinyu.pojo.Customer"
*/
@Test
public void testPage() {
String jpql = "FROM com.it.fuxinyu.pojo.Customer";
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Query query = entityManager.createQuery(jpql);
query.setFirstResult(0);
query.setMaxResults(3);
List resultList = query.getResultList();
System.out.println(resultList);
transaction.commit();
entityManager.close();
}
xxxxxxxxxx
/**
* 条件查询
* 案例: 查询客户以赵开头客户
* sql: SELET*FROM
* jpql: "FROM com.it.fuxinyu.pojo.Customer";
*/
@Test
public void testCondition() {
String jpql = "FROM com.it.fuxinyu.pojo.Customer WHERE custName LIKE ?";
EntityManager entityManager = JpaUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Query query = entityManager.createQuery(jpql);
//占位符位置 从1开始
int position = 1;
query.setParameter(position, "赵%");
List resultList = query.getResultList();
System.out.println(resultList);
transaction.commit();
entityManager.close();
}
day2:springdatajpa的运行原理以及基本操作
一.springDataJpa的概述
I.简述
Spring Data JPA是较大的Spring Data系列的一部分,可轻松实现基于JPA的存储库。该模块处理对基于JPA的数据访问层的增强支持。它使构建使用数据访问技术的Spring支持的应用程序变得更加容易。
实现应用程序的数据访问层已经很长一段时间了。为了执行简单查询以及执行分页和审核,必须编写太多样板代码。Spring Data JPA旨在通过将工作量减少到实际需要的数量来显着改善数据访问层的实现。作为开发人员,您将编写包括自定义finder方法在内的存储库接口,Spring会自动提供实现。
II.特性
- 基于Spring和JPA构建存储库的先进支持
- 支持Querydsl谓词,从而支持类型安全的JPA查询
- 域类的透明审核
- 分页支持,动态查询执行,集成自定义数据访问代码的能力
@Query
引导时验证带注释的查询- 支持基于XML的实体映射
- 通过引入基于JavaConfig的存储库配置
@EnableJpaRepositories
。
III.简图
二.springDataJpa的入门操作
案例:客户的基本CRUD
I.搭建环境
1.创建工程导入坐标
xxxxxxxxxx
<properties>
<spring.version>4.2.4.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.20</mysql.version>
</properties>
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</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>
<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 -->
<!--druid beg-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!--druid 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>
<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>4.2.4.RELEASE</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>
2.配置spring的配置文件
xxxxxxxxxx
<?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: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/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/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">
<!--注解扫描-->
<context:component-scan base-package="com.it.fuxinyu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--引入jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--druid数据库连接池-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${druid.driverClassName}"/>
<property name="url" value="${druid.url}"/>
<property name="username" value="${druid.username}"/>
<property name="password" value="${druid.password}"/>
<!--防止SQL注入-->
<property name="filters" value="${druid.filters}"/>
<!--最大并发连接数-->
<property name="maxActive" value="${druid.maxActive}"/>
<!--初始化连接数-->
<property name="initialSize" value="${druid.initialSize}"/>
<!--超时时间-->
<property name="maxWait" value="${druid.maxWait}"/>
<!--最小空闲连接数-->
<property name="minIdle" value="${druid.minIdle}"/>
<!--检测间隔-->
<property name="timeBetweenConnectErrorMillis" value="${druid.timeBetweenEvictionRunsMillis}"/>
<!--最小存活时间-->
<property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}"/>
<!--测试数据库是否存活-->
<property name="validationQuery" value="${druid.validationQuery}"/>
<!-- 如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 -->
<property value="${druid.testWhileIdle}" name="testWhileIdle"/>
<!-- 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 默认为true 修改为false -->
<property value="${druid.testOnBorrow}" name="testOnBorrow"/>
<property value="${druid.testOnReturn}" name="testOnReturn"/>
<property value="${druid.maxOpenPreparedStatements}" name="maxOpenPreparedStatements"/>
<!-- 超过时间限制是否回收 -->
<property value="${druid.removeAbandoned}" name="removeAbandoned"/>
<!-- 超过时间限制多长 1800秒,也就是30分钟 -->
<property value="${druid.removeAbandonedTimeout}" name="removeAbandonedTimeout"/>
<!-- 关闭abanded连接时输出错误日志 -->
<property value="${druid.logAbandoned}" name="logAbandoned"/>
</bean>
<!--数据管理工厂-->
<bean id="entityManagerFactoryBean"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="druidDataSource"/>
<!--配置扫描的包(实体类所在的包)-->
<property name="packagesToScan" value="com.it.fuxinyu.pojo"/>
<!--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"/>
<property name="showSql" value="true"/>
</bean>
</property>
<!--jpa方言-->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<!-- JPA事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryBean"/>
</bean>
<!-- 整合spring data jpa-->
<jpa:repositories base-package="com.it.fuxinyu.dao"
transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactoryBean"/>
<!-- 4.txAdvice-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.Exception"
read-only="false"/>
<tx:method name="insert*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.Exception"
read-only="false"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.Exception"
read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.Exception"
read-only="false"/>
<tx:method name="get*" read-only="true" isolation="DEFAULT" propagation="REQUIRED"
rollback-for="java.lang.Exception"/>
<tx:method name="find*" read-only="true" isolation="DEFAULT" propagation="REQUIRED"
rollback-for="java.lang.Exception"/>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.Exception"
read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 5.aop-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.it.fuxinyu.service.impl.*.*(..)))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
</beans>
3.编写实体类(Customer),使用jpa注解配置映射关系
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import javax.persistence.*;
import java.io.Serializable;
/**
* 客户实体类
* 配置映射关系
* 1.实体类和表的映射关系
* 2.实体类中属性和表字段的映射关系
* 使用注解
* <p>
* 1.表操作
*
* @Entity javax.persistence.Entity; 配置实体类和表的映射关系
* @Table 配置实体类和表的映射关系
* name: 配置数据库表的名称
* <p>
* 2.字段操作 配置实体类中属性和表中字段的映射关系
* 主键配置
*/
@Entity
@Table(name = "cst_customer")
public class Customer implements Serializable {
private static final long serialVersionUID = -2382852293113450787L;
/**
* 客户编号(主键)
*
* @Id 声明主键的配置
* @GeneratedValue 配置主键的生成策略
* strategy
* GenerationType.IDENTITY 自增 数据库必须支持自动增长
* GenerationType.SEQUENCE 自增 数据库必须支持序列
* GenerationType.TABLE 自增 数据库必须支持序列
* @Colunm 配置属性和字段的映射关系
* 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_industry")
private String custIndustry;
/**
* 客户级别
*/
@Column(name = "cust_level")
private String custLevel;
/**
* 客户联系地址
*/
@Column(name = "cust_address")
private String custAddress;
/**
* 客户联系电话
*/
@Column(name = "cust_phone")
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custLevel='" + custLevel + '\'' +
", custAddress='" + custAddress + '\'' +
", custPhone='" + custPhone + '\'' +
'}';
}
}
II.编写一个符合springDataJpa的dao层接口
1.只需要编写dao层接口不需要dao层接口的实现类
2.需要提供相应的泛型
- <Customzer, Long>
- Customzer 实体类类型
- Long 主键类型
xxxxxxxxxx
package com.it.fuxinyu.dao;
import com.it.fuxinyu.pojo.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* 符合springData的dao层规范
*/
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
}
III.基本增删改查测试案例
- findOne 根据id查询
- save 需要传递实体对象 如果实体类有id则为更新操作 否则为增加操作
- delete 传递id 根据id进行删除
- findAll 查询所有
xxxxxxxxxx
/**
* 测试查询by主键
*/
@Test
public void testFindOne() {
Customer one = customerDao.findOne(Long.valueOf(3));
System.out.println(one);
}
xxxxxxxxxx
/**
* 测试存储
*/
@Test
public void testSave() {
Customer customer = new Customer();
customer.setCustName("无敌飞腿");
customer.setCustAddress("大明神王");
customerDao.save(customer);
}
xxxxxxxxxx
/**
* 测试修改
* 依然是save方法 如果实体类有id则为更新操作
*/
@Test
public void testUpdate() {
Customer customer = new Customer();
customer.setCustId(7l);
customer.setCustName("飞雷神");
customer.setCustAddress("宇智波臭弟弟");
customerDao.save(customer);
}
xxxxxxxxxx
/**
* 测试删除
*/
@Test
public void testDelete() {
Long id = 7l;
customerDao.delete(id);
}
xxxxxxxxxx
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<Customer> all = customerDao.findAll();
System.out.println(all);
}
三.springDataJpa的运行过程和原理剖析
I.疑问?
只有接口没有实现怎么工作的呢?
II.分析
xxxxxxxxxx
//jdk动态代理
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable
xxxxxxxxxx
//为我们创建代理对象
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
xxxxxxxxxx
//提供了对接口中的增删改查方法的实现
public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T>
xxxxxxxxxx
//采用了JPA规范
private final EntityManager em;
III.原理图
- 通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象
- 通过SimpleJpaRepository当中封装了JPA的操作(借助了JPA的api完成数据库的crud)
- 通过Hibernate完成数据库操作(封装了jdbc)
四.复杂查询
I.借助接口定义好的查询
- count 查询总数量
- exists 判断数据是否存在
- getOne 根据id查询 底层由getReference实现 延迟加载 (懒加载)
xxxxxxxxxx
/**
* 查询总记录数
*/
@Test
public void testCount() {
long count = customerDao.count();
System.out.println(count);
}
xxxxxxxxxx
/**
* 判断数据是否存在
*/
@Test
public void testExists() {
boolean exists = customerDao.exists(6l);
System.out.println(exists);
}
xxxxxxxxxx
/**
* 根据id查询 懒加载
*/
@Test
@Transactional
public void testGetOne() {
Customer one = customerDao.getOne(6l);
System.out.println(one);
}
II.jpql查询
jpql:jpa query language (jpa查询语言)
特点语法或者关键字和sql语句类似
查询的是类和类中的属性
需要将JPQL语句配置到接口方法上
- 特有的查询:需要在dao接口上配置方法
- 在新添加的方法上,使用注解的形式配jpql查询
- 注解:@Query
自定义jpql方法
xxxxxxxxxx
@Query(value = "from com.it.fuxinyu.pojo.Customer WHERE custName = ?")
public Customer findCustomerByJpql(String custName);
xxxxxxxxxx
/**
* 测试jpql 根据名称查询
*/
@Test
public void testJpqlQuery() {
Customer angie = customerDao.findCustomerByJpql("邵丹做个人吧");
System.out.println(angie);
}
xxxxxxxxxx
@Query(value = "from com.it.fuxinyu.pojo.Customer WHERE custName = ? and custId = ?")
public Customer findByCustNameAndCustId(String custName, Long custId);
xxxxxxxxxx
/**
* 测试jpql 根据名称、Id查询
*/
@Test
public void testFindByCustNameAndCustId() {
Customer angie = customerDao.findByCustNameAndCustId("xxx",6l);
System.out.println(angie);
}
xxxxxxxxxx
//默认参数和占位符类型对应 可以采用?加索引来 指定参数传递如下
@Query(value = "from com.it.fuxinyu.pojo.Customer WHERE custName = ?2 and custId = ?1")
public Customer findByCustNameAndCustId(Long custId, String custName);
xxxxxxxxxx
@Query(value = "UPDATE com.it.fuxinyu.pojo.Customer SET custName = ?2 where custId = ?1")
@Modifying
public void updateByCustNameAndCustId(Long custId, String custName);
xxxxxxxxxx
/**
* 测试jpql 根据名称 Id修改
* 接口删改类必须加上@Modifying 调用方法必须加上@Transactional springDataJPA会自动回滚 必须手动取消 @Rollback(value = false)
*/
@Test
@Transactional
@Rollback(value = false)
public void updateByCustNameAndCustId() {
customerDao.updateByCustNameAndCustId(9l, "xxx");
}
III.sql语句的查询
-
特有的查询:需要在dao接口上配置方法
-
在新添加的方法上,使用注解形式配置sql查询语句
-
注解@Query
value:jpql|sql
nativeQuery:false(使用jpql查询)|true(使用本地查询:sql查询)
xxxxxxxxxx
/**
* 使用sql查询
* sql: SELECT*FROM cst_customer
*/
@Query(value = "SELECT*FROM cst_customer", nativeQuery = true)
public List<Object[]> findAllUseSql();
xxxxxxxxxx
/**
* 查询全部根据sql
*/
@Test
public void testFindAllBySql() {
List<Object[]> allUseSql = customerDao.findAllUseSql();
for (Object[] objects : allUseSql) {
System.out.println(Arrays.toString(objects));
}
}
IV.按照命名规则进行查询
findBy:查询
对象中的属性名(首字母大写):查询的条件
CustName
*.默认情况:使用等于的方式查询
*.特殊的方式查询
在springdataJpa的运行阶段
会根据方法名称进行解析 findBy from xxx (实体类) 属性名称 where custName =
1.findBy+属性名称(根据属性名称进行匹配的查询)
2.findBy+属性名称+查询方式(Like | isNull)
3.findBy+属性名称+查询方式+多条件的连接符+(and|or)+属性名+查询方式
精准匹配
xxxxxxxxxx
/**
* 使用姓名查询
*
* @return
*/
public Customer findByCustName(String custName);
xxxxxxxxxx
/**
* 查询根据姓名
*/
@Test
public void testFindByCustNameUseSql() {
Customer angie = customerDao.findByCustName("xxx");
System.out.println(angie);
}
模糊查询
xxxxxxxxxx
/**
* 使用姓名查询
*
* @return
*/
public List<Customer> findByCustNameIsLike(String custName);
xxxxxxxxxx
/**
* 查询根据姓名
*/
@Test
public void testFindByCustNameUseSql() {
List<Customer> angie = customerDao.findByCustNameIsLike("%赵%");
System.out.println(angie);
}
多条件模糊查询
xxxxxxxxxx
/**
* 按客户名称与客户行业查询
*
* @return
*/
public List<Customer> findByCustNameLikeAndAndCustIndustry(String custName,String custIndustry);
xxxxxxxxxx
/**
* 查询根据姓名
*/
@Test
public void findByCustNameLikeAndAndCustIndustry() {
List<Customer> angie = customerDao.findByCustNameLikeAndAndCustIndustry("%飞%","s");
System.out.println(angie);
}
day3.多表操作,复杂查询
一.回顾与今日内容介绍
I.回顾
i.springDatajpa,jpa规范,hibernate三者之间的关系
- code → springDatajpa → jpa规范的API → hibernate
ii.符合springDataJpa规范的dao层接口的编写规则
- 需要实现两个接口(JpaRepository,JapSpecificationExecutor)
- 提供响应的泛型
iii.运行过程
iv.查询
II.今日内容介绍
i.Specifications动态查询
-
xxxxxxxxxx
T findOne(Specification<T> spec);//查询一条
-
xxxxxxxxxx
List<T> findAll(Specification<T> spec);//查询全部
-
xxxxxxxxxx
Page<T> findAll(Specification<T> spec, Pageable pageable);//查询全部分页
Pageable pageable //分页参数
//返回值pageBean(page:是springdatajpa提供的)
-
xxxxxxxxxx
List<T> findAll(Specification<T> spec, Sort sort);
//sort 排序参数
-
xxxxxxxxxx
long count(Specification<T> spec);//统计查询
Specification:查询条件
自定义自己的Specification实现类
实现
xxxxxxxxxx
//封装查询条件
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
- root查询的跟对象查询的任何属性都可以从跟对象中获取
- query 顶层查询对象,自定义查询方式(了解:一般不用)
- cb 查询的构造器,封装了很多查询条件
xxxxxxxxxx
/**
* 根据条件,查询单个对象
*/
@Test
public void testFindOne() {
/**
* 匿名内部类
* 自定义查询条件
* 1.实现Specification接口(提供泛型,查询对象的类型)
* 2.实现toPredicate方法(构造)
* 3.需要借助方法参数中两个参数(
* root:”获取需要查询的对象属性“
* CriteriaBuilder:"构造查询条件的,内部封装了很多的查询条件(模糊匹配,精确匹配)"
* )
* 案例:根据客户名称查询,查询客户为传智播客的客户
* 查询条件
* 1.查询方式
* cb对象
* 2.比较的属性名称
* root对象
*/
Specification<Customer> specification = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//1.获取比较的属性
Path<Object> custName = root.get("custName");
Path<Object> custIndustry = root.get("custIndustry");
//2.构造查询条件:select*from cst_customer where cust_name = '传智播客'
Predicate pI = cb.equal(custName, "赵雅芝");
Predicate pII = cb.equal(custIndustry, "wdxx");
//3.将多个查询条件组合到一起,组合(满足条件一,满足条件二,与关系.满足条件一或者条件二即可,或关系);
Predicate and = cb.and(pI, pII);//以与的形式将多个查询条件
// Predicate or = cb.or(pI, pII);//以与的形式将多个查询条件
return and;
}
};
Customer one = customerDao.findOne(specification);
System.out.println(one);
}
xxxxxxxxxx
/**
* 案例 完成根据客户名称的模糊匹配 返回客户列表
* 客户名称以 传智播客 开头
* equal 直接到path对象(属性) 然后进行比较即可
* gt lt ge le like 得到path对象根据path指定比较的参数类型,再去进行比较
* 指定参数类型 path as(类型·的字节码对象) 得到 Expression
*/
@Test
public void testFindAll() {
Specification<Customer> tSpecification = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//查询属性: 客户名
Path<Object> custName = root.get("custName");
//查询方式: 模糊匹配
Predicate like = cb.like(custName.as(String.class), "%赵%");
return like;
}
};
List<Customer> all = customerDao.findAll(tSpecification);
for (Customer customer : all) {
System.out.println(customer);
}
}
xxxxxxxxxx
/**
* 案例 完成根据客户名称的模糊匹配 返回客户列表
* 客户名称以 传智播客 开头
* equal 直接到path对象(属性) 然后进行比较即可
* gt lt ge le like 得到path对象根据path指定比较的参数类型,再去进行比较
* 指定参数类型 path as(类型·的字节码对象) 得到 Expression
*/
@Test
public void testFindAll() {
Specification<Customer> tSpecification = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//查询属性: 客户名
Path<Object> custName = root.get("custName");
//查询方式: 模糊匹配
Predicate like = cb.like(custName.as(String.class), "%赵%");
return like;
}
};
Sort sort = new Sort(Sort.Direction.ASC, "custId");
List<Customer> all = customerDao.findAll(tSpecification, sort);
for (Customer customer : all) {
System.out.println(customer);
}
}
xxxxxxxxxx
/**
* 分页查询
* Specification: 查询条件
* Pageable: 分页参数
* findAll(Specification,Pageable) 带有条件的分页
* findAll(Pageable): 没有条件的分页
* 返回Page(springDataJpa为我们封装好的pageBean对象,数据列表,共条数)
*/
@Test
public void testPage() {
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return null;
}
};
PageRequest pageable = new PageRequest(1, 3);
Page<Customer> all = customerDao.findAll(spec, pageable);
long totalElements = all.getTotalElements();
int totalPages = all.getTotalPages();
List<Customer> content = all.getContent();
System.out.println(totalElements);
System.out.println(totalPages);
for (Customer customer : content) {
System.out.println(customer);
}
}
xxxxxxxxxx
/**
* 查询总记录数
*/
@Test
public void testCount() {
Specification<Customer> spec = (root, query, cb) -> {
Predicate like = cb.like(root.get("custName").as(String.class), "赵%");
return like;
};
long count = customerDao.count(spec);
System.out.println(count);
}
ii.多表之间的关系和操作多表的操作步骤
-
表关系
-
一对一
-
一对多:
- 一的一方:主表
- 多的一方:从表
- 外键:需要再从表上新建一列作为外键,他的取值源于主表的主键
-
多对多
- 中间表:中间表最少应该有两个字段组成,这两个字段作为外键指向两张表的主键,又组成了联合主键
-
-
图解
讲师对学员:一个对多个
实体类中的关系
- 包含关系:可以通过实体类中包含关系描述表关系
- 继承关系
分析步骤
- 明确表与表关系
- 确定表关系 (描述 外键 | 中间表)
- 编写实体类,再实体类中描述表关系(包含关系)
- 配置映射关系
iii.完成多表操作
1.一对多
案例:客户和联系人案例
客户:一家公司
联系人:这家公司的员工
一个客户可以具有多个联系人
一个联系人从属于一家公司
分析步骤
-
明确表与表关系
一对多关系
-
确定表关系 (描述 外键 | 中间表)
主表:客户表
从表: 联系人表
再从表上添加外键
-
编写实体类 再实体类中描述表关系(包含关系)
客户:在客户实体类中包含一个联系人的集合
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import javax.persistence.*;
import java.io.Serializable;
/**
* 客户的实体类
* 明确使用的注解都是JPA规范的
* 所以导包都要导入javax.persistence包下的
*/
@Entity//表示当前类是一个实体类
@Table(name = "cst_customer")//建立当前实体类和表之间的对应关系
public class Customer implements Serializable {
private static final long serialVersionUID = 6022395004710550525L;
@Id//表明当前私有属性是主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//指定主键的生成策略
@Column(name = "cust_id")//指定和数据库表中的cust_id列对应
private Long custId;
@Column(name = "cust_name")//指定和数据库表中的cust_name列对应
private String custName;
@Column(name = "cust_source")//指定和数据库表中的cust_source列对应
private String custSource;
@Column(name = "cust_industry")//指定和数据库表中的cust_industry列对应
private String custIndustry;
@Column(name = "cust_level")//指定和数据库表中的cust_level列对应
private String custLevel;
@Column(name = "cust_address")//指定和数据库表中的cust_address列对应
private String custAddress;
@Column(name = "cust_phone")//指定和数据库表中的cust_phone列对应
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custLevel='" + custLevel + '\'' +
", custAddress='" + custAddress + '\'' +
", custPhone='" + custPhone + '\'' +
'}';
}
}
联系人:再联系人的实体类中包含一个客户的对象
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import javax.persistence.*;
import java.io.Serializable;
/**
* 联系人的实体类(数据模型)
*/
@Entity
@Table(name = "cst_linkman")
public class LinkMan implements Serializable {
private static final long serialVersionUID = -4114464554259983651L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "lkm_id")
private Long lkmId;
@Column(name = "lkm_name")
private String lkmName;
@Column(name = "lkm_gender")
private String lkmGender;
@Column(name = "lkm_phone")
private String lkmPhone;
@Column(name = "lkm_mobile")
private String lkmMobile;
@Column(name = "lkm_email")
private String lkmEmail;
@Column(name = "lkm_position")
private String lkmPosition;
@Column(name = "lkm_memo")
private String lkmMemo;
public Long getLkmId() {
return lkmId;
}
public void setLkmId(Long lkmId) {
this.lkmId = lkmId;
}
public String getLkmName() {
return lkmName;
}
public void setLkmName(String lkmName) {
this.lkmName = lkmName;
}
public String getLkmGender() {
return lkmGender;
}
public void setLkmGender(String lkmGender) {
this.lkmGender = lkmGender;
}
public String getLkmPhone() {
return lkmPhone;
}
public void setLkmPhone(String lkmPhone) {
this.lkmPhone = lkmPhone;
}
public String getLkmMobile() {
return lkmMobile;
}
public void setLkmMobile(String lkmMobile) {
this.lkmMobile = lkmMobile;
}
public String getLkmEmail() {
return lkmEmail;
}
public void setLkmEmail(String lkmEmail) {
this.lkmEmail = lkmEmail;
}
public String getLkmPosition() {
return lkmPosition;
}
public void setLkmPosition(String lkmPosition) {
this.lkmPosition = lkmPosition;
}
public String getLkmMemo() {
return lkmMemo;
}
public void setLkmMemo(String lkmMemo) {
this.lkmMemo = lkmMemo;
}
@Override
public String toString() {
return "LinkMan{" +
"lkmId=" + lkmId +
", lkmName='" + lkmName + '\'' +
", lkmGender='" + lkmGender + '\'' +
", lkmPhone='" + lkmPhone + '\'' +
", lkmMobile='" + lkmMobile + '\'' +
", lkmEmail='" + lkmEmail + '\'' +
", lkmPosition='" + lkmPosition + '\'' +
", lkmMemo='" + lkmMemo + '\'' +
'}';
}
}
4.配置映射关系
使用jpa注解配置实一对多映射关系
客户→联系人
xxxxxxxxxx
/**
* 配置客户和联系人之间的关系(一对多关系)
* 使用注解的形式配置多表关系
* 1.声明关系
*
* @OneToMany: 配置一对多关系
* targetEntity:对方对象的字节码对象
* <p>
* 2.配置外键(中间表)
* @JoinColumn: 配置外键
* name: 外键字段名称
* referencedColumnName:参照的主表的主字段名称
* 在客户实体类上(一的一方)添加了外键的配置,所以对应客户而已,也具备了维护外键的作用
*/
// @OneToMany(targetEntity = LinkMan.class)
// @JoinColumn(name = "lkm_cust_id", referencedColumnName = "cust_id")
@OneToMany(mappedBy = "customer")
private List<LinkMan> linkManList = new ArrayList<>();
联系人→客户
xxxxxxxxxx
/**
* 配置联系人到客户的多对一关系
* 使用注解的形式配置多对一
* 1.配置表关系
*
* @ManyToOne:配置多对一关系 targetEntity:对方的实体类字节码
* <p>
* 2.配置外键(中间表)
* 配置外键的过程,配置到了多的一方就会在多的一方进行维护
*/
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "lkm_cust_id", referencedColumnName = "cust_id")
private Customer customer;
方法演示
xxxxxxxxxx
/**
* 保存一个客户保存一个联系人
* 效果客户和联系人作为独立的数据保存到数据库中
* 联系人的外键为空
* 原因?
* 实体类中没有配置关系
* <p>
* 会有一条多余的update语句
*/
@Test
@Transactional
@Rollback(value = false)
public void testAdd() {
//创建一个联系人
Customer customer = new Customer();
customer.setCustName("泷谷源治");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("芹泽多摩雄");
/**
* 配置了客户到联系人的关系
* 从客户的角度上,发送两条insert语句,发送一条更新语句更新数据库(更新外键)
* 由于我们配置了客户到联系人的关系,客户可以对外键进行维护
*
* 由于配置了一的一方到多的一方的关联关系,所以会发送一条update语句
*
* 解决此问题只需要在一的一方放弃维护
*/
// customer.getLinkManList().add(linkMan);
//由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经发送语句)
linkMan.setCustomer(customer);
customerDao.save(customer);
linkManDao.save(linkMan);
}
级联:
操作一个对象的同时操作他的管理对象
级联操作
- 需要区分操作主体
- 需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系注解上)
- cascade 配置级联
级联添加
案例:当我保存一个客户的同时保存联系人
级联删除
案例:当我删除一个客户的同时删除此客户的所有联系人
测试案例
在配置中添加一行
xxxxxxxxxx
//update不会删除表
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
在主表实体类中加入一个配置
xxxxxxxxxx
推荐ALL
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
private List<LinkMan> linkManList = new ArrayList<>();
xxxxxxxxxx
cascade
CascadeType.ALL 所有
CascadeType.PERSIST 存储
CascadeType.MERGE 修改
CascadeType.REMOVE 删除
xxxxxxxxxx
/**
* 级联增加
*/
@Test
public void testCascadeAdd() {
//创建一个联系人
Customer customer = new Customer();
customer.setCustName("泷谷源治1");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("芹泽多摩雄2");
linkMan.setCustomer(customer);
customer.getLinkManList().add(linkMan);
customerDao.save(customer);
}
xxxxxxxxxx
/**
* 级联删除
*/
@Test
public void testCascadeDelete() {
//创建一个联系人
Customer customer = customerDao.findOne(1l);
customerDao.delete(customer);
}
2.多对多
案例:用户和角色(多对多关系)
用户:
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "tb_name")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long userId;
@Column(name = "user_name")
private String userName;
@Column(name = "user_age")
private Integer userAge;
private Set<Role> roleSet = new HashSet<>();
public Set<Role> getRoleSet() {
return roleSet;
}
public void setRoleSet(Set<Role> roleSet) {
this.roleSet = roleSet;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAge=" + userAge +
", roleSet=" + roleSet +
'}';
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
}
角色:s
xxxxxxxxxx
package com.it.fuxinyu.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "tb_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Long roleId;
@Column(name = "role_name")
private String roleName;
private Set<User> userSet = new HashSet<>();
public Set<User> getUserSet() {
return userSet;
}
public void setUserSet(Set<User> userSet) {
this.userSet = userSet;
}
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleName='" + roleName + '\'' +
", userSet=" + userSet +
'}';
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
分析步骤
-
明确表关系
多对多关系
-
确定表关系(描述外键|中间表)
中间表
-
编写实体类,再实体类中描述表关系(包含关系)
用户:包含角色的集合
角色:包含用户的集合
-
配置映射关系
用户
xxxxxxxxxx
// @ManyToMany(targetEntity = Role.class)
// @JoinTable(name = "tb_user_role", joinColumns = {
// //joinColumns,当前对象在中间表中的外键
// @JoinColumn(name = "tb_user_id", referencedColumnName = "user_id")
// //inverseJoinColumns,对方对象在中间表的外键
// }, inverseJoinColumns = {
// @JoinColumn(name = "tb_role_id", referencedColumnName = "role_id")
// })
@ManyToMany(mappedBy = "userSet")
private Set<Role> roleSet = new HashSet<>();
public Set<Role> getRoleSet() {
return roleSet;
}
public void setRoleSet(Set<Role> roleSet) {
this.roleSet = roleSet;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAge=" + userAge +
", roleSet=" + roleSet +
'}';
}
角色
xxxxxxxxxx
/**
* 配置多对多映射关系
* 1.声明表关系的配置
*
* @ManyToMany(targetEntity = User.class)//多对多
* targetEntity = User.class 代表对方的实体类字节码
* 2.配置中间表(包含两个外键)
* @JoinTable name: 中间表名称
* joinColumns: 配置当前对象在中间表的外键
* @JoinColumn的数组 name 外键名称
* referencedColumnName:参照的主表的主键名
* inverseJoinColumns:配置对方对象在中间表的主键名
* @JoinColumn的数组 name 外键名称
* referencedColumnName:参照的主表的主键名
*/
@ManyToMany(targetEntity = User.class)
@JoinTable(name = "tb_user_role", joinColumns = {
//joinColumns,当前对象在中间表中的外键
@JoinColumn(name = "tb_role_id", referencedColumnName = "role_id")
//inverseJoinColumns,对方对象在中间表的外键
}, inverseJoinColumns = {
@JoinColumn(name = "tb_user_id", referencedColumnName = "user_id")
})
private Set<User> userSet = new HashSet<>();
public Set<User> getUserSet() {
return userSet;
}
public void setUserSet(Set<User> userSet) {
this.userSet = userSet;
}
测试案例
xxxxxxxxxx
@Test
@Transactional
@Rollback(value = false)
public void testAdd() {
User user = new User();
user.setUserName("霹雳火");
Role role = new Role();
role.setRoleName("java程序员");
userDao.save(user);
roleDao.save(role);
}
@Test
@Transactional
@Rollback(value = false)
public void testAddII() { //这个是放弃维护权后操作的
User user = new User();
user.setUserName("ssasd霹雳2");
Role role = new Role();
role.setRoleName("java程2dasdas序员");
//谁被调用谁放弃维护权
user.getRoleSet().add(role);
role.getUserSet().add(user);
userDao.save(user);
roleDao.save(role);
}
总结
当两个表多对多是 同时维护主键会冲突需要被调用方放弃维护权 在注解中配置@ManyToMany(mappedBy = "userSet") 并执行另一方的当前对象集合属性名
级联
在操作主体上加入casecade = Cascade.All
xxxxxxxxxx
@ManyToMany(mappedBy = "userSet", cascade = CascadeType.ALL)
级联操作
级联增加
xxxxxxxxxx
@Test
public void testCascadeAdd() {
User user = new User();
user.setUserName("ssasd霹雳2");
Role role = new Role();
role.setRoleName("java程2dasdas序员");
user.getRoleSet().add(role);
role.getUserSet().add(user);
userDao.save(user);
}
级联删除
xxxxxxxxxx
@Test
public void testCascadeDelete() {
// User one = userDao.findOne(1L);
Role role = roleDao.findOne(4l);
roleDao.delete(role);
}
iv.对象图导航检索
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。
例如:我们通过ID查询方式查出一个客户,可以调用Customer类中的getLinkMans()方法来获取该客户的所有联系人。
对象导航查询的使用要求是:两个对象之间必须存在关联关系。
我们查询客户时,要不要把联系人查询出来?
如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的,不使用时又会白白的浪费了服务器内存。
采用延迟加载的思想。通过配置的方式来设定当我们在需要使用时,发起真正的查询。
1.一对多
对于一对多的情况,我们在客户实体类(一的一方)进行查询,SpringDataJpa默认是延迟加载的。
xxxxxxxxxx
//测试对象导航查询(查询一个对象的时候,通过此对象查询所有的关联对象)
@Test
@Transactional // 解决在java代码中的no session问题(could not initialize proxy - no Session)
public void testQuery1() {
//查询id为2的客户
Customer customer = customerDao.getOne(2l);
//对象导航查询,此客户下的所有联系人
Set<LinkMan> linkMans = customer.getLinkMans();
for (LinkMan linkMan : linkMans) {
System.out.println(linkMan);
}
}
延迟加载发起的是两个sql语句
xxxxxxxxxx
SELECT
customer0_.cust_id AS cust_id1_0_0_,
customer0_.cust_address AS cust_add2_0_0_,
customer0_.cust_industry AS cust_ind3_0_0_,
customer0_.cust_level AS cust_lev4_0_0_,
customer0_.cust_name AS cust_nam5_0_0_,
customer0_.cust_phone AS cust_pho6_0_0_,
customer0_.cust_source AS cust_sou7_0_0_
FROM
cst_customer customer0_
WHERE customer0_.cust_id = ?
xxxxxxxxxx
SELECT
linkmans0_.lkm_cust_id AS lkm_cust9_1_0_,
linkmans0_.lkm_id AS lkm_id1_1_0_,
linkmans0_.lkm_id AS lkm_id1_1_1_,
linkmans0_.lkm_cust_id AS lkm_cust9_1_1_,
linkmans0_.lkm_email AS lkm_emai2_1_1_,
linkmans0_.lkm_gender AS lkm_gend3_1_1_,
linkmans0_.lkm_memo AS lkm_memo4_1_1_,
linkmans0_.lkm_mobile AS lkm_mobi5_1_1_,
linkmans0_.lkm_name AS lkm_name6_1_1_,
linkmans0_.lkm_phone AS lkm_phon7_1_1_,
linkmans0_.lkm_position AS lkm_posi8_1_1_
FROM
cst_linkman linkmans0_
WHERE linkmans0_.lkm_cust_id = ?
也可以在实体类中配置fetch = FetchType.EARGE采用立即加载,立即加载发起一个sql语句
xxxxxxxxxx
SELECT
customer0_.cust_id AS cust_id1_0_0_,
customer0_.cust_address AS cust_add2_0_0_,
customer0_.cust_industry AS cust_ind3_0_0_,
customer0_.cust_level AS cust_lev4_0_0_,
customer0_.cust_name AS cust_nam5_0_0_,
customer0_.cust_phone AS cust_pho6_0_0_,
customer0_.cust_source AS cust_sou7_0_0_,
linkmans1_.lkm_cust_id AS lkm_cust9_1_1_,
linkmans1_.lkm_id AS lkm_id1_1_1_,
linkmans1_.lkm_id AS lkm_id1_1_2_,
linkmans1_.lkm_cust_id AS lkm_cust9_1_2_,
linkmans1_.lkm_email AS lkm_emai2_1_2_,
linkmans1_.lkm_gender AS lkm_gend3_1_2_,
linkmans1_.lkm_memo AS lkm_memo4_1_2_,
linkmans1_.lkm_mobile AS lkm_mobi5_1_2_,
linkmans1_.lkm_name AS lkm_name6_1_2_,
linkmans1_.lkm_phone AS lkm_phon7_1_2_,
linkmans1_.lkm_position AS lkm_posi8_1_2_
FROM
cst_customer customer0_
LEFT OUTER JOIN cst_linkman linkmans1_
ON customer0_.cust_id = linkmans1_.lkm_cust_id
WHERE customer0_.cust_id = ?
我们知道getOne是延迟加载的,findOne是立即加载的,为了说明关联关系中一的一方默认是延迟加载的,我们使用findOne,发现依然是延迟加载的,依然是发起两次sql查询的。
xxxxxxxxxx
@Test
@Transactional // 解决在java代码中的no session问题
public void testQuery2() {
//查询id为2的客户
Customer customer = customerDao.findOne(2l);
//对象导航查询,此客户下的所有联系人
Set<LinkMan> linkMans = customer.getLinkMans();
System.out.println(linkMans.size());
}
2.多对多
我们也可以在多的一方进行查询,SpringDataJpa在多的一方默认是立即加载的
xxxxxxxxxx
@Test
@Transactional // 解决在java代码中的no session问题
public void testQuery3() {
LinkMan linkMan = linkManDao.findOne(2l);
//对象导航查询所属的客户
Customer customer = linkMan.getCustomer();
System.out.println(customer);
}
语句如下
xxxxxxxxxx
SELECT
linkman0_.lkm_id AS lkm_id1_1_0_,
linkman0_.lkm_cust_id AS lkm_cust9_1_0_,
linkman0_.lkm_email AS lkm_emai2_1_0_,
linkman0_.lkm_gender AS lkm_gend3_1_0_,
linkman0_.lkm_memo AS lkm_memo4_1_0_,
linkman0_.lkm_mobile AS lkm_mobi5_1_0_,
linkman0_.lkm_name AS lkm_name6_1_0_,
linkman0_.lkm_phone AS lkm_phon7_1_0_,
linkman0_.lkm_position AS lkm_posi8_1_0_,
customer1_.cust_id AS cust_id1_0_1_,
customer1_.cust_address AS cust_add2_0_1_,
customer1_.cust_industry AS cust_ind3_0_1_,
customer1_.cust_level AS cust_lev4_0_1_,
customer1_.cust_name AS cust_nam5_0_1_,
customer1_.cust_phone AS cust_pho6_0_1_,
customer1_.cust_source AS cust_sou7_0_1_
FROM
cst_linkman linkman0_
LEFT OUTER JOIN cst_customer customer1_
ON linkman0_.lkm_cust_id = customer1_.cust_id
WHERE linkman0_.lkm_id = ?
day4:springboot整合springdataJpa
I.搭建环境
i.引入坐标
xxxxxxxxxx
<dependencies>
<!--jpa所需jar包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
ii.配置yaml
xxxxxxxxxx
server:
port: 8081
spring:
datasource:
hikari:
jdbc-url: jdbc:mysql://127.0.0.1:3306/db_jpa?serverTimezone=GMT%2B8
password: root
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
#jpa的配置
jpa:
show-sql: true
hibernate:
ddl-auto: update
II.介绍几个核心接口
i. Repository接口
功能
- 提供了方法名称命名查询与方式
- 提供了基于@Query注解查询与更新
使用方法
方法名称必须遵循驼峰式命名规则,findBy(update|delete..关键字) + 属性名(首字母大写)+查询条件( and| like|or.. 首字母大写)
xxxxxxxxxx
/**
* 方法名称命名查询
*/
public interface UserRepositoryByName extends Repository<User, Long> {
/**
* 根据用户名查询
* @param userName
* @return
*/
List<User> findByUserName(String userName);
}
xxxxxxxxxx
/**
* 根据用户名查询
*/
@Test
@Transactional
@Rollback(value = false)
void testFindByUserName() {
List<User> list = byName.findByUserName("邵丹做个人吧");
for (User user : list) {
System.out.println(user);
}
}
基于Query注解的查询
xxxxxxxxxx
/**
* 测试jpql
*
* @param userName
* @return
*/
@Query(value = "from User WHERE userName = :userName")
List<User> queryByUserNameUseJPQL(@Param("userName") String userName);
/**
* 测试sql
* 必须加上 nativeQuery = true 默认为false
*
* @param userName
* @return
*/
@Query(value = "select *from tb_name WHERE user_name = ?1", nativeQuery = true)
List<User> queryByUserNameUseSQL(String userName);
xxxxxxxxxx
/**
* 测试query注解
*/
@Test
@Transactional
@Rollback(value = false)
void testQueryJpql() {
List<User> list = annotation.queryByUserNameUseJPQL("邵丹做个人吧");
for (User user : list) {
System.out.println(user);
}
}
/**
* 测试query注解
*/
@Test
@Transactional
@Rollback(value = false)
void testQuerySql() {
List<User> list = annotation.queryByUserNameUseSQL("邵丹做个人吧");
for (User user : list) {
System.out.println(user);
}
}
注意修改时 必须加上@Modifying注解 调用的方法必须加上事务@Transactional和@Rollback(value = false)
xxxxxxxxxx
ava/**
* 修改
*
* @param userName
* @param userId
*/
@Query(value = "update User set userName = ?1 where userId = ?2")
@Modifying
void updateUseJpql(String userName, Long userId);
xxxxxxxxxx
/**
* 测试query注解
*/
@Test
@Transactional
@Rollback(value = false)
void testUpdateJpql() {
annotation.updateUseJpql("无敌风火轮", 5l);
}
ii. CrudRepository接口
功能
count 计算总记录数 delete删除 deleteAll批量删除 deleteAll批量删除 deleteById主键删除 existsById判断是否存在 findAll查询全部 findAllById根据id查询全部 findById查询根据主键 save增加 saveAll批量增加
使用方法
iii. PagingAndSortingRepository接口
功能
使用方法
xxxxxxxxxx
@Autowired
private UserRepositoryCrudRepository crudRepository;
@Test
public void testSave() {
User user = new User();
user.setUserId(8L);
user.setUserName("张铁林");
User save = crudRepository.save(user);
System.out.println(save);
}
@Test
@Transactional
@Rollback(value = false)
public void testFindOne() {
User user = new User();
user.setUserId(8L);
user.setUserName("张铁林");
Optional<User> byId = crudRepository.findById(8l);
User user1 = byId.get();
System.out.println(user1);
}
@Test
@Transactional
@Rollback(value = false)
public void testFindAll() {
User user = new User();
user.setUserId(8L);
user.setUserName("张铁林");
Iterable<User> all = crudRepository.findAll();
all.forEach(System.out::println);
}
@Test
@Transactional
@Rollback(value = false)
public void testDelete() {
User user = new User();
user.setUserId(8L);
user.setUserName("张铁林");
Iterable<User> all = crudRepository.findAll();
crudRepository.deleteAll(all);
}
@Test
@Transactional
@Rollback(value = false)
public void testInsertAll() {
User user = new User();
user.setUserId(8L);
user.setUserName("张铁林");
Role role = new Role();
role.setRoleName("6666");
User user1 = new User();
user1.setUserName("张铁林1");
Role role1 = new Role();
role1.setRoleName("77777");
User user2 = new User();
user2.setUserName("张铁林2");
Role role2 = new Role();
role2.setRoleName("8888");
user.getRoleSet().add(role);
user1.getRoleSet().add(role1);
user2.getRoleSet().add(role2);
role.getUserSet().add(user);
role1.getUserSet().add(user1);
role2.getUserSet().add(user2);
List<User> list = new ArrayList<>();
list.add(user);
list.add(user1);
list.add(user2);
crudRepository.saveAll(list);
}