回顾
i.springDatajpa,jpa规范,hibernate三者之间的关系
code -- > springDatajpa --> jpa规范的API --> hibernate
ii.符合springDataJpa规范的dao层接口的编写规则
1.需要实现两个接口(JpaRepository,JapSpecificationExecutor)
2.提供响应的泛型
iii.运行过程
* 动态代理的方式:动态代理对象
iiii.查询
第一 Specifications动态查询
对于JpaSpecificationExecutor,这个接口基本是围绕着Specification接口来定义的。我们可以简单的理解为,Specification构造的就是查询条件。
JpaSpecificationExecutor 方法列表
T findOne(Specification<T> spec); //查询单个对象
List<T> findAll(Specification<T> spec); //查询列表
//查询全部,分页
//pageable:分页参数
//返回值:分页pageBean(page:是springdatajpa提供的)
Page<T> findAll(Specification<T> spec, Pageable pageable);
//查询列表
//Sort:排序参数
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);//统计查询
* Specification :查询条件
//Specification接口中只定义了如下一个方法:
构造查询条件
/**
* root :Root接口,代表查询的根对象,可以通过root获取实体中的属性
* query :代表一个顶层查询对象,用来自定义查询
* cb :用来构建查询,此对象里有很多条件方法
**/
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
自定义我们自己的Specification实现类
实现
//root:查询的根对象(查询的任何属性都可以从根对象中获取)
//CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
//CriteriaBuilder:查询的构造器,封装了很多的查询条件
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); //封装查询条件
package com.test;
import com.test.dao.CustomerDao;
import com.test.domain.Customer;
import javassist.runtime.Desc;
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;
/**
* @author 琴宝宝
* @version V1.0
* @Package com.test
* @date 2022/3/28 16:26
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpecTest {
@Autowired
private CustomerDao customerDao;
/**
* 根据条件,查询单个对象
*/
@Test
public void testSpec(){
Specification<Customer> spec=new Specification<Customer>() {
//匿名内部类
/**
* 自定义查询条件
* 1.实现Specification接口(提供泛型:查询的对象类型)
* 2.实现toPredicate方法(构造查询条件)
* 3.需要借助方法参数中的两个参数(
* root:获取需要查询的对象属性
* CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配)
* )
* 案例:根据客户名称查询,查询客户名为啦啦啦1的客户
* 查询条件
* 1.查询方式
* cb对象
* 2.比较的属性名称
* root对象
*/
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custName = root.get("custName");
Predicate equal = criteriaBuilder.equal(custName, "啦啦啦1");
return equal;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
/**
* 多条件查询
* 案例:根据客户名和客户所属行业查询
*/
@Test
public void testSpec1(){
Specification<Customer> spec=new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
Path<Object> custName = root.get("custName");
Path<Object> custIndustry = root.get("custIndustry");
Predicate p1 = cb.equal(custName, "啦啦啦1");
Predicate p2 = cb.equal(custIndustry, "IT");
Predicate and = cb.and(p1, p2);
return and;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
/**
* 模糊查询
*/
@Test
public void testLike(){
Specification<Customer> spec =new Specification<Customer>() {
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;
}
};
Sort sort=new Sort(Sort.Direction.DESC,"custId");
List<Customer> l = customerDao.findAll(spec,sort);
for (Customer customer : l) {
System.out.println(customer);
}
}
/**
* 分页查询
*/
@Test
public void testPage(){
Specification<Customer> spec=null;
Pageable page=new PageRequest(0,3);
Page<Customer> list = customerDao.findAll(spec, page);
System.out.println(list.getTotalElements());
System.out.println(list.getTotalPages());
System.out.println(list.getContent());
}
}
-
- 方法对应关系
方法名称 |
Sql对应关系 |
equle |
filed = value |
gt(greaterThan ) |
filed > value |
lt(lessThan ) |
filed < value |
ge(greaterThanOrEqualTo ) |
filed >= value |
le( lessThanOrEqualTo) |
filed <= value |
notEqule |
filed != value |
like |
filed like value |
notLike |
filed not like value |
第二 多表之间的关系和操作多表的操作步骤
表关系
一对一
一对多:
一的一方:主表
多的一方:从表
外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键
多对多:
中间表:中间表中最少应该由两个字段组成,这两个字段做为外键指向两张表的主键,又组成了联合主键
讲师对学员:一对多关系
实体类中的关系
包含关系:可以通过实体类中的包含关系描述表关系
继承关系
分析步骤
1.明确表关系
2.确定表关系(描述 外键|中间表)
3.编写实体类,再实体类中描述表关系(包含关系)
4.配置映射关系
映射的注解说明
@OneToMany:
作用:建立一对多的关系映射
属性:
targetEntityClass:指定多的多方的类的字节码
mappedBy:指定从表实体类中引用主表对象的名称。
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
orphanRemoval:是否使用孤儿删除
@ManyToOne
作用:建立多对一的关系
属性:
targetEntityClass:指定一的一方实体类字节码
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
optional:关联是否可选。如果设置为false,则必须始终存在非空关系。
@JoinColumn
作用:用于定义主键字段和外键字段的对应关系。
属性:
name:指定外键字段的名称
referencedColumnName:指定引用主表的主键字段名称
unique:是否唯一。默认值不唯一
nullable:是否允许为空。默认值允许。
insertable:是否允许插入。默认值允许。
updatable:是否允许更新。默认值允许。
columnDefinition:列的定义信息。
package com.test;
import com.test.dao.CustomerDao;
import com.test.dao.LinkManDao;
import com.test.domain.Customer;
import com.test.domain.LinkMan;
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;
/**
* @author 琴宝宝
* @version V1.0
* @Package com.test
* @date 2022/4/18 22:04
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class onetomanyTest {
@Autowired
private CustomerDao customerDao;
@Autowired
private LinkManDao linkManDao;
@Test
@Transactional
@Rollback(false)
public void save(){
Customer customer=new Customer();
customer.setCustName("百度");
LinkMan linkMan=new LinkMan();
linkMan.setLkmName("张三");
customer.getLinkMans().add(linkMan);
customerDao.save(customer);
linkManDao.save(linkMan);
}
@Test
@Transactional
@Rollback(false)
public void save1(){
Customer customer=new Customer();
customer.setCustName("百度");
LinkMan linkMan=new LinkMan();
linkMan.setLkmName("张三");
linkMan.setCustomer(customer);
customerDao.save(customer);
linkManDao.save(linkMan);
}
@Test
@Transactional
@Rollback(false)
public void save2(){
Customer customer=new Customer();
customer.setCustName("百度");
LinkMan linkMan=new LinkMan();
linkMan.setLkmName("张三");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
customerDao.save(customer);
linkManDao.save(linkMan);
}
@Test
@Transactional
@Rollback(false)
public void cascadeTest(){
Customer customer=new Customer();
customer.setCustName("百度1");
LinkMan linkMan=new LinkMan();
linkMan.setLkmName("张三1");
customerDao.save(customer);
linkManDao.save(linkMan);
}
@Test
@Transactional
@Rollback(false)
public void cascadeRemoveTest(){
Customer customer = customerDao.findOne(2l);
customerDao.delete(2l);
}
}
第三 完成多表操作
i.一对多操作
案例:客户和联系人的案例(一对多关系)
客户:一家公司
联系人:这家公司的员工
一个客户可以具有多个联系人
一个联系人从属于一家公司
分析步骤
1.明确表关系
一对多关系
2.确定表关系(描述 外键|中间表)
主表:客户表
从表:联系人表
* 再从表上添加外键
3.编写实体类,再实体类中描述表关系(包含关系)
客户:再客户的实体类中包含一个联系人的集合
联系人:在联系人的实体类中包含一个客户的对象
4.配置映射关系
* 使用jpa注解配置一对多映射关系
映射的注解说明
@ManyToMany
作用:用于映射多对多关系
属性:
cascade:配置级联操作。
fetch:配置是否采用延迟加载。
targetEntity:配置目标的实体类。映射多对多的时候不用写。
@JoinTable
作用:针对中间表的配置
属性:
nam:配置中间表的名称
joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段
inverseJoinColumn:中间表的外键字段关联对方表的主键字段
@JoinColumn
作用:用于定义主键字段和外键字段的对应关系。
属性:
name:指定外键字段的名称
referencedColumnName:指定引用主表的主键字段名称
unique:是否唯一。默认值不唯一
nullable:是否允许为空。默认值允许。
insertable:是否允许插入。默认值允许。
updatable:是否允许更新。默认值允许。
columnDefinition:列的定义信息。
级联:
操作一个对象的同时操作他的关联对象
级联操作:
1.需要区分操作主体
2.需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上)
3.cascade(配置级联)
级联添加,
案例:当我保存一个客户的同时保存联系人
级联删除
案例:当我删除一个客户的同时删除此客户的所有联系人
ii.多对多操作
案例:用户和角色(多对多关系)
用户:
角色:
分析步骤
1.明确表关系
多对多关系
2.确定表关系(描述 外键|中间表)
中间间表
3.编写实体类,再实体类中描述表关系(包含关系)
用户:包含角色的集合
角色:包含用户的集合
4.配置映射关系
package test;
import com.test.dao.RoleDao;
import com.test.dao.UserDao;
import com.test.domain.Role;
import com.test.domain.User;
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;
/**
* @author 琴宝宝
* @version V1.0
* @Package test
* @date 2022/4/18 23:33
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ManyToManyTest {
@Autowired
private UserDao userDao;
@Autowired
private RoleDao roleDao;
@Test
@Transactional
@Rollback(false)
public void SaveTest(){
User user=new User();
user.setUserName("admin");
Role role=new Role();
role.setRoleName("System");
user.getRoles().add(role);
role.getUsers().add(user);
userDao.save(user);
roleDao.save(role);
}
@Test
@Transactional
@Rollback(false)
public void RemoveTest(){
userDao.findOne(1l);
userDao.delete(1l);
}
}
iii.多表的查询
1.对象导航查询
查询一个对象的同时,通过此对象查询他的关联对象
案例:客户和联系人
从一方查询多方
* 默认:使用延迟加载(****)
从多方查询一方
* 默认:使用立即加载
package com.test;
import com.test.dao.CustomerDao;
import com.test.dao.LinkManDao;
import com.test.domain.Customer;
import com.test.domain.LinkMan;
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.Set;
/**
* @author 琴宝宝
* @version V1.0
* @Package com.test
* @date 2022/4/18 22:04
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ObjectQueryTest {
@Autowired
private CustomerDao customerDao;
@Autowired
private LinkManDao linkManDao;
@Test
@Transactional
public void Query1(){
Set<LinkMan> linkMans = customerDao.getOne(1l).getLinkMans();
for (LinkMan linkMan : linkMans) {
System.out.println(linkMan);
}
}
/**
* 对象导航查询:
* 默认使用的是延迟加载的形式查询的
* 调用get方法并不会立即发送查询,而是在使用关联对象的时候才会差和讯
* 延迟加载!
* 修改配置,将延迟加载改为立即加载
* fetch,需要配置到多表映射关系的注解上
*
*/
@Test
@Transactional
public void Query2(){
Set<LinkMan> linkMans = customerDao.getOne(1l).getLinkMans();
for (LinkMan linkMan : linkMans) {
System.out.println(linkMan);
}
}
@Test
@Transactional
public void Query3(){
LinkMan one = linkManDao.findOne(2l);
System.out.println(one);
}
}