Spring Data JPA进一步学习

上次有介绍Spring Data JPA 接口实现的第一个接口JpaRepository,这次说一下动态查询, 第二个接口JpaSpecificationExecutor进行操作和Spring Data JPA 如何操作多表

在这里插入图片描述

接口有简单几个方法:主要是参数就是查询条件有关于分页的查询,需要实现对应的Pageable接口,可以看到有一个都是使用的接口Specification,下面来说一下:

在这里插入图片描述

进入接口可以看见它只实现了一个方法

 若是多个参数进行对此进行规则构造   然后将多个属性进行逻辑拼接
此方法有三个参数:
	Root:是根对象,属性都可以从中获取    使用 Entity e = root.get(xxx);
	CriteriaQuery:顶层的查询对象,自定义查询对象  有逻辑方法,可以自定义去设计
	CriteriaBuilder:查询构造器,封装的是规则

在这里插入图片描述

​ Predicate predicate = cb.equal(e,“xxxx”)
​ 返回predicate即可

​ 可以看到里面就是我们平时使用的规则在这里插入图片描述

基本方法列表:

方法名称Sql对应关系
equlefiled = value
gt(greaterThan )filed > value
lt(lessThan )filed < value
ge(greaterThanOrEqualTo )filed >= value
le( lessThanOrEqualTo)filed <= value
notEqulefiled != value
likefiled like value
notLikefiled not like value

基本使用:

@Test	
public void test() {
  Specification<Student> specification = new Specification(){
     public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
       	//使用root根获取我们需要的属性
       Path name = root.get("StuName");
       //使用构造进行查询和返回Predicate   
       //并且执行是使用JPQL语句    :name = ?
       Predicate predicate = criteriaBuilder.equal(name,"xxx");
       return Predicate;
     }
  };
}

多个查询条件使用cb对象连接:

Path name = root.get("StuName");
Path age = root.get("StuAge");
Predicate p1 = criteriaBuilder.like(name,"xxx");
Predicate p2 = criteriaBuilder.equal(age,xxx);
return criteriaBuilder.and(p1,p2);//拼接

Sort接口:有封装很多方法常用有这个枚举

在这里插入图片描述

Specification<Customer> specification = new Specification() {
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
              Path StuID = root.get("StuID");
            };
Sort sort = new Sort(Sort.Direction.DESC,StuId);
List list = stuDao.findAll(specification,sort);

分页接口封装了我们常使用的方法:

在这里插入图片描述

实现类有用PageRequest类,在这里插入图片描述

​ 分页返回page对象 主要有getContent方法、getTotalPages方法、getTotalElements方法

Specification<Customer> specification = new Specification() {
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
              Path xxx = root.xxx("xxx");
            };
Pageable pageable = new PageRequest(0,1);//每次查询1个,从第0页开始
Page<Student> all = StuDao.findAll(specification, pageable);
System.out.println(all.getContent());
System.out.println(all.getTotalElements());
System.out.println(all.getTotalPages());

多表关系操作多表

一对多操作:客户和联系人
一般将一的一方称作为主表,多的一方称作从表,在数据库中建立一对多的关系需要使用到外键约束

​ 客户(主)对应对个联系人(从)

在实体类中体现方式为

​ 主表有一个属性集合,存放的就是从表数据,采用注解方式进行配置
​ 声明关系:一对多关系

​ 参数是多的一方的实体字节码文件

​ @OneToMany(targetEntity=从表实体.class)
​ 然后配置外键(中间表)

​ @JointColumn(name=“数据库外键”,referencedColumn=“主表的主键”)

@OneToMany(targetEntity=Link.class)  //主表配置一对多关系
@JoinColumn(name="link_cust_id",ReferencedColumnName="cust_id")//配置中间表 
private Set<Link> linkSet;//主表的属性结合

从表实体中体现方式是有一个客户对象
声明关系:一对多关系
@ManyToOne(targetEntity=主表实体.class)
配置外键(中间表)
@JointColumn(name=“数据库外键”,referencedColumn=“主表的主键”)

配置外键的过程,配置到了多的一方,就会在多的一方维护外键

@ManyToOne(targetEntity=Customer.class)  //从表配置多对一关系
@JoinColumn(name="link_cust_id",ReferencedColumnName="cust_id")//配置中间表 
private Customer customer;

在两方都进行配置就是双向的一对多关系

注解详情:

  • @OneToMany
    • 用于建立一对多关系
    • targetEntityClass:指定多的方的字节码文件
    • mappedBy:指定从表实体类引用主表对象的名称
    • cascade:指定是否需要使用级联操作
    • fetch:指定是否延迟加载
  • @ManyToOne
    • 用于建立多对一关系
    • targetEntityClass:指定多的方的字节码文件
    • cascade:指定是否需要使用级联操作
    • fetch:指定是否延迟加载
  • @JoinColumn
    • 用于定义主键字段与外键字段的对应关系
    • name:指定外键字段的名称
    • referencedColumnName:指定用于主表的主键字段名称
    • unique:是否唯一,默认允许
    • nullable:是否允许为空,默认允许
    • insertable:是否允许插入,默认允许
    • updatable:是否允许更新表,默认允许
    • columnDefinition:列的定义信息

测试:

添加操作:

要求:创建用户对象和联系人对象、建立关系(一对多关系)、保存(先保存主表信息,再存从表信息)

@Transactional  //事务
@Rollback(value = false)//回滚false

//必须添加实体之间的关系然后再进行添加数据  否则不会建立连接   就是外键无效

Customer customer = new Customer();
LinkMan linkMan = new LinkMan();
customer.getLinkMans().add(linkMan);//此方法建立一对多关系联系,产生两个insert和一个update
linkMan.setCustomer(customer);//此方法建立多对一关系联系,产生两个insert

//保存
customerDao.save(customer);
linkManDao.save(linkMan);

产生的问题:

​ 两条insert语句,和一条维护的表关系update语句,而在实际开发中,我们只需要两个inset语句

在这里插入图片描述

保存语句 主表配置关系会有新的sql语句,update产生
而从表建立关系没有产生多余的update语句

那我们的解决是思路很简单,在一对多的一的方向放弃维护关系
@OneToMany(mappedBy=“customer”)

在这里插入图片描述

删除操作:删除操作也有约束

  1. 删除从表时候可以进行任意删除

  2. 删除主表数据时候

  • 从表有数据情况
    • 默认情况下,将外键字段设置为null,然后将主表数据删除,如果数据库默认外键约束不为空,则会出现报错
    • 如果配置了主表放弃维护外键关系,则不能删除(与数据库设置不为null无关),因为再删除时候就不会去更新从表的数据
  • 从表没有数据,随便删除

在实际开发中,级联删除慎用

级联删除:
操作一个同时操作它的关联对象

1.注意操作主体   主需要在操作主体上进行配置cascade
2.在操作的主题类上进行添加主题属性(配置在多表映射的注解上    OneToMany3.cascade(配置级联) CascadeType.范围

配置信息:

在这里插入图片描述

CascadeType.MERGE 级联更新

* CascadeType.PERSIST 级联保存:

* CascadeType.REFRESH 级联刷新:

* CascadeType.REMOVE 级联删除:

* CascadeType.ALL 包含所有

@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,fetch = FetchType.EAGER)

添加
保存客户也保存联系人

删除
删除客户也保存联系人

多对多和一对多基本差不多,简单说一下

比如一个人与角色的关系就是多对多的

一个人可以有多个角色:所以User实体类里存角色对象就是一个集合:

@ManyToMany(targetEntity=Role.class,cascade=CascadeType.ALL)//使用多对多注解
@JoinTable(name="tbl_user_role",//中间表的名称
          JoinColumns={      @JointColumns(name="tab_user_role_userid",referencedColunmName="user_id")}, //当前对象在中间表的字段和中间表字段名称对应关系       @inverseJoinColumns{@JoinCloulmn(name="tab_user_role_userid"),referenedColumnName="role_id"}//对方对象在中间表的字段和中间表字段名称对应关系    
          )
private Set<Role> roleSet = new HashSet<Role>();

一个角色可以对应多个人,也是集合:

@ManyToMany(mapperBy="roleSet")  //设置映射
private Set<User> userSet = new HashSet<User>();

@ManyToMany:设置多对多关系映射表

@JointTable:

  • 针对中间表的配置
  • name:中间表的名称
  • @JoinColumns:中间表的外键字段与当前对象实体类所对应的表的主键
  • @inverseJoinColumns:中间表的外键字段与关联对象实体类所对应的表的主键

多对多操作:

还是放弃两边同时维护中间表,只一方进行维护,防止出现主键冲突问题

在多对多的删除时,双向级联删除根本不能配置。禁用

如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据

删除:先删除中间表信息

Spring Data JPA的多表查询:
多表的查询:
对象导航查询:OGNL 查询一个对象同时通过此对象查询关联的对象

在这里插入图片描述

对象.getLinkMans方法 需要添加@Transcation注解 解决no session问题

默认使用的是延迟加载

修改配置:设置加多表映射的注解上:fetch

当查询为一对多的时候采用延迟加载,而是多对一时候,使用立即加载

Specification查询:

Specification spec = new Specification() {
    public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
        Join<LinkMan,Customer> customer = root.join("customer", JoinType.INNER);//连接查询
        return criteriaBuilder.like(customer.<String>get("custName").as(String.class),"1");//查了名称为1的关联对象

    }
};
List all = linkManDao.findAll(spec);
System.out.println(all);

在这里插入图片描述

也可以实现关联查询:

Join:代表链接查询,通过root对象获取

创建的过程中,第一个参数为关联对象的属性名称,第二个参数为连接查询的方式(left,inner,right)

JoinType.LEFT : 左外连接;JoinType.INNER:内连接;JoinType.RIGHT:右外连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值