前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring的学习笔记(十七)——SpringDataJpa动态查询和复杂的多表操作

Spring的学习笔记(十七)——SpringDataJpa动态查询和复杂的多表操作

作者头像
不愿意做鱼的小鲸鱼
发布2022-09-26 17:57:26
3.4K0
发布2022-09-26 17:57:26
举报
文章被收录于专栏:web全栈

Specifications动态查询

有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。

JpaSpecificationExecutor 方法列表

代码语言:javascript
复制
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实现类

代码语言:javascript
复制
    实现
        //root:查询的根对象(查询的任何属性都可以从根对象中获取)
        //CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
        //CriteriaBuilder:查询的构造器,封装了很多的查询条件
        Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); //封装查询条件

分别用Specification实现: 1. 精确查询 2. 模糊查询 3. 多条件查询 4. 排序查询 5. 分页查询

代码如下

代码语言:javascript
复制
package cn.kt.test;/*
 *Created by tao on 2020-05-05.
 */

import cn.kt.dao.CustomerDao;
import cn.kt.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;

    /*
     * 根据条件查询单个对象
     * 自定义查询条件
        1.实现Specification接口(提供泛型:查询的对象类型)
        2.实现toPredicate方法(构造查询条件)
        3.需要借助方法参数中的两个参数(
            root:获取需要查询的对象属性
            CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配)

            查询条件:
            1. 查询方式:
                cb对象
            2. 比较属性的名称
                oot对象
        )
     * */
    @Test
    public void testSepc1() {
        Specification<Customer> sprec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //1. 获取比较的属性
                Path<Object> custName = root.get("custName");
                //2. 构造查询的条件    第一个参数,path (属性),第二个参数,属性的取值
                Predicate equal = criteriaBuilder.equal(custName, "左眼会陪右眼哭");
                return equal;
            }
        };
        Customer customer = customerDao.findOne(sprec);
        System.out.println(customer);
    }

    /*
    * 多条件查询
    * root:获取属性
        客户名
        所属行业
      cb:构造查询
        1.构造客户名的精准匹配查询
        2.构造所属行业的精准匹配查询
        3.将以上两个查询联系起来
    * */
    @Test
    public void testSepc2() {
        Specification<Customer> sprec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //1. 获取比较的属性
                Path<Object> custName = root.get("custName");//客户名
                Path<Object> custAddress = root.get("custAddress");//地址
                //2. 构造查询的条件  第一个参数,path (属性),第二个参数,属性的取值
                Predicate p1 = criteriaBuilder.equal(custName, "左眼会陪右眼哭");
                Predicate p2 = criteriaBuilder.equal(custAddress, "江西赣州");
                //3. 将多个条件组合到一起(满足条件一并且满足条件二,满足条件一或者满足条件二)
                Predicate and = criteriaBuilder.and(p1, p2);//以与的形式拼接多个条件
                //Predicate or = criteriaBuilder.or();//以或的形式拼接多个条件
                return and;
            }
        };
        Customer customer = customerDao.findOne(sprec);
        System.out.println(customer);
    }

    /*完成根据客户名称的模糊匹配,返回客户列表
        equal :直接的到path对象(属性),然后进行比较即可
        gt, lt,ge,le,like
        得到path对象, 根据path指定比较的参数类型,再去进行比较
        指定参数类型: path.as (类型的字节码对象)
     */
    @Test
    public void testSepc3() {
        Specification<Customer> sprec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //1. 获取比较的属性
                Path<Object> custName = root.get("custName");//客户名
                //2. 构造查询的条件:模糊查询
                Predicate like = criteriaBuilder.like(custName.as(String.class), "%吉%");
                return like;
            }
        };
        List<Customer> all = customerDao.findAll(sprec);
        for (Customer customer : all) {
            System.out.println(customer);
        }

        //添加排序
        //创建排序对象,需要调用构造方法实例化sort对象
        //第一个参数:排序的顺序(倒序,正序)
        // Sort .Direction. DESC:倒序
        // Sort . Direction.ASC :升序
        //第二个参数:排序的属性名称
        System.out.println("****************排序实现的***************");
        Sort sort = new Sort(Sort.Direction.DESC,"custId");
        List<Customer> list = customerDao.findAll(sprec, sort);
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

    /*分页查询
    Specification:查询条件
    Pageable:分页参数
    分页参数:查询的页码,每页查询的条数
    findAll(Specification, Pageable):带有条件的分页
    findA1l(Pageable):没有条件的分页
    返回:Page (sptingDataJpa为我们封装好的pageBean对象,数据列表,共条数)
    */
    @Test
    public void testPage() {
        //构造查询条件
        Specification<Customer> spec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.like(root.get("custName").as(String.class), "%吉%");
            }
        };

        /**
         * 构造分页参数
         *      Pageable : 接口
         *          PageRequest实现了Pageable接口,调用构造方法的形式构造
         *              第一个参数:页码(从0开始)
         *              第二个参数:每页查询条数
         */
        Pageable pageable = new PageRequest(0, 5);

        /**
         * 分页查询,封装为Spring Data Jpa 内部的page bean
         *      此重载的findAll方法为分页方法需要两个参数
         *          第一个参数:查询条件Specification
         *          第二个参数:分页参数
         */
        Page<Customer> page = customerDao.findAll(spec,pageable);
        System.out.println(pageable);
        System.out.println(page.getContent());//得到数据集合列表
        System.out.println(page.getTotalElements());//得到总条数
        System.out.println(page.getTotalPages());//得到总页数
    }
}

多表之间的关系和操作

多表之间的关系和操作多表的操作步骤

  • 表关系 一对一 一对多: 一的一方:主表 多的一方:从表 外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键 多对多: 中间表:中间表中最少应该由两个字段组成,这两个字段做为外键指向两张表的主键,又组成了联合主键
  • 讲师对学员:一对多关系
  • 实体类中的关系 包含关系:可以通过实体类中的包含关系描述表关系 继承关系
  • 分析步骤 1.明确表关系 2.确定表关系(描述 外键|中间表) 3.编写实体类,再实体类中描述表关系(包含关系) 4.配置映射关系

完成多表操作

映射的注解说明
  • @OneToMany: 作用:建立一对多的关系映射 属性: targetEntityClass:指定多的多方的类的字节码 mappedBy:指定从表实体类中引用主表对象的名称。 cascade:指定要使用的级联操作 fetch:指定是否采用延迟加载 orphanRemoval:是否使用孤儿删除
  • @ManyToOne 作用:建立多对一的关系 属性: targetEntityClass:指定一的一方实体类字节码 cascade:指定要使用的级联操作 fetch:指定是否采用延迟加载 optional:关联是否可选。如果设置为false,则必须始终存在非空关系。
  • @JoinColumn 作用:用于定义主键字段和外键字段的对应关系。 属性: name:指定外键字段的名称 referencedColumnName:指定引用主表的主键字段名称 unique:是否唯一。默认值不唯一 nullable:是否允许为空。默认值允许。 insertable:是否允许插入。默认值允许。 updatable:是否允许更新。默认值允许。 columnDefinition:列的定义信息。
i.一对多操作
代码语言:javascript
复制
    案例:客户和联系人的案例(一对多关系)
        客户:一家公司
        联系人:这家公司的员工

        一个客户可以具有多个联系人
        一个联系人从属于一家公司

    分析步骤
        1.明确表关系
            一对多关系
        2.确定表关系(描述 外键|中间表)
            主表:客户表
            从表:联系人表
                * 再从表上添加外键
        3.编写实体类,再实体类中描述表关系(包含关系)
            客户:再客户的实体类中包含一个联系人的集合
            联系人:在联系人的实体类中包含一个客户的对象
        4.配置映射关系
            * 使用jpa注解配置一对多映射关系

    级联:
        操作一个对象的同时操作他的关联对象

        级联操作:
            1.需要区分操作主体
            2.需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上)
            3.cascade(配置级联)
        级联添加,
            案例:当我保存一个客户的同时保存联系人
        级联删除
            案例:当我删除一个客户的同时删除此客户的所有联系人
保存操作
代码语言:javascript
复制
 @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testAdd() {
        Customer c = new Customer();
        c.setCustName("TBD云集中心");
        c.setCustLevel("VIP客户");
        c.setCustSource("网络");
        c.setCustIndustry("商业办公");
        c.setCustAddress("昌平区北七家镇");
        c.setCustPhone("010-84389340");

        LinkMan l = new LinkMan();
        l.setLkmName("TBD联系人");
        l.setLkmGender("male");
        l.setLkmMobile("13811111111");
        l.setLkmPhone("010-34785348");
        l.setLkmEmail("98354834@qq.com");
        l.setLkmPosition("老师");
        l.setLkmMemo("还行吧");
        c.getLinkmans().add(l);
        l.setCustomer(c);
        customerDao.save(c);
        linkManDao.save(l);
    }

通过保存的案例,我们可以发现在设置了双向关系之后,会发送两条insert语句,一条多余的update语句,那我们的解决是思路很简单,就是一的一方放弃维护权

代码语言:javascript
复制
/**
     *放弃外键维护权的配置将如下配置改为
     */
    //@OneToMany(targetEntity=LinkMan.class)
//@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")    
//设置为
    @OneToMany(mappedBy="customer")
级联

首先要配置级联属性 在配置一对多关系是添加一下注解

代码语言:javascript
复制
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
    private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);
级联添加,
代码语言:javascript
复制
案例:当我保存一个客户的同时保存联系人
代码语言:javascript
复制
/*
    * 级联添加:保存一个客户的同时,保存客户的所有联系人
        需要在操作主体的实体类上, 配置casacde属性
    */
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testCascadeAdd() {
        Customer c = new Customer();
        c.setCustName("TBD云集中心");
        c.setCustLevel("VIP客户");
        c.setCustSource("网络");
        c.setCustIndustry("商业办公");
        c.setCustAddress("昌平区北七家镇");
        c.setCustPhone("010-84389340");

        LinkMan l = new LinkMan();
        l.setLkmName("TBD联系人");
        l.setLkmGender("male");
        l.setLkmMobile("13811111111");
        l.setLkmPhone("010-34785348");
        l.setLkmEmail("98354834@qq.com");
        l.setLkmPosition("老师");
        l.setLkmMemo("还行吧");
        c.getLinkmans().add(l);
        l.setCustomer(c);
        customerDao.save(c);
    }
级联删除
代码语言:javascript
复制
案例:当我删除一个客户的同时删除此客户的所有联系人
代码语言:javascript
复制
/*
     * 级联删除:
     * 删除一号客户的同时,删除一号客户的所有联系人
     */
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testCascadeRemove() {
        //1. 查询1号客户
        Customer one = customerDao.findOne(2l);
        //2. 删除1号客户
        customerDao.delete(one);
    }
ii.多对多操作
代码语言:javascript
复制
    案例:用户和角色(多对多关系)
        用户:
        角色:

    分析步骤
        1.明确表关系
            多对多关系
        2.确定表关系(描述 外键|中间表)
            中间间表
        3.编写实体类,再实体类中描述表关系(包含关系)
            用户:包含角色的集合
            角色:包含用户的集合
        4.配置映射关系
多对多操作案例
  1. 多对多保存操作(放弃维护权)
  2. 级联添加操作
  3. 级联删除操作

映射的注解说明 * @ManyToMany 作用:用于映射多对多关系 属性: cascade:配置级联操作。 fetch:配置是否采用延迟加载。 targetEntity:配置目标的实体类。映射多对多的时候不用写。

  • @JoinTable 作用:针对中间表的配置 属性: nam:配置中间表的名称 joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段 inverseJoinColumn:中间表的外键字段关联对方表的主键字段
  • @JoinColumn 作用:用于定义主键字段和外键字段的对应关系。 属性: name:指定外键字段的名称 referencedColumnName:指定引用主表的主键字段名称 unique:是否唯一。默认值不唯一

代码如下 1.SysUser.java(用户的数据模型)

代码语言:javascript
复制
package cn.kt.domain;/*
 *Created by tao on 2020-05-06.
 */

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * 用户的数据模型
 */
@Entity
@Table(name = "sys_user")
public class SysUser implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long userId;
    @Column(name = "user_code")
    private String userCode;
    @Column(name = "user_name")
    private String userName;
    @Column(name = "user_password")
    private String userPassword;
    @Column(name = "user_state")
    private String userState;

    /*
    * 配置用户到角色的多对多关系
        配置多对多的映射关系
        1.声明表关系的配置
            @ManyToMany(mappedBy = SysRole.class) //多对多
            targetEntity 对方实体类字节码

        2.配置中间表(包含两个外键)
            JoinTable
                name:中间表的名称
                joinColumns配置当前对象在中间表中的外键
                inverseJoinColumns配置对方对象在中间表中的外键
    * */
    @ManyToMany(targetEntity = SysRole.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",
            //joinColumns配置当前对象在中间表中的外键
            joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
            //inverseJoinColumns配置对方对象在中间表中的外键
            inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}
    )

    private Set<SysRole> roles = new HashSet<SysRole>(0);

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getUserCode() {
        return userCode;
    }

    public void setUserCode(String userCode) {
        this.userCode = userCode;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserState() {
        return userState;
    }

    public void setUserState(String userState) {
        this.userState = userState;
    }

    public Set<SysRole> getRoles() {
        return roles;
    }

    public void setRoles(Set<SysRole> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "SysUser [userId=" + userId + ", userCode=" + userCode + ", userName=" + userName + ", userPassword="
                + userPassword + ", userState=" + userState + "]";
    }
}
  1. SysRole.java(角色的数据模型)
代码语言:javascript
复制
package cn.kt.domain;/*
 *Created by tao on 2020-05-06.
 */

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * 角色的数据模型
 */
@Entity
@Table(name="sys_role")
public class SysRole implements Serializable {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="role_id")
    private Long roleId;
    @Column(name="role_name")
    private String roleName;
    @Column(name="role_memo")
    private String roleMemo;

    //多对多关系映射
    @ManyToMany(mappedBy = "roles")
    private Set<SysUser> users = new HashSet<SysUser>(0);


    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;
    }
    public String getRoleMemo() {
        return roleMemo;
    }
    public void setRoleMemo(String roleMemo) {
        this.roleMemo = roleMemo;
    }
    public Set<SysUser> getUsers() {
        return users;
    }
    public void setUsers(Set<SysUser> users) {
        this.users = users;
    }
    @Override
    public String toString() {
        return "SysRoleDao [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
    }
}
  1. ManyToManyTest.java(测试)
代码语言:javascript
复制
package cn.kt.test;/*
 *Created by tao on 2020-05-06.
 */

import cn.kt.dao.SysRoleDao;
import cn.kt.dao.SysUserDao;
import cn.kt.domain.SysRole;
import cn.kt.domain.SysUser;
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;

@RunWith(SpringJUnit4ClassRunner.class)  //声明单元测试
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ManyToManyTest {
    @Autowired
    private SysUserDao userDao;
    @Autowired
    private SysRoleDao roleDao;

    /**
     * 需求:
     * 保存用户和角色
     * 要求:
     * 创建2个用户和3个角色
     * 让1号用户具有1号和2号角色(双向的)
     * 让2号用户具有2号和3号角色(双向的)
     * 保存用户和角色
     * 问题:
     * 在保存时,会出现主键重复的错误,因为都是要往中间表中保存数据造成的。
     * 解决办法:
     * 让任意一方放弃维护关联关系的权利
     * 一般让被动的一方放弃维护权
     */
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testAdd() {
        //创建对象
        SysUser u1 = new SysUser();
        u1.setUserName("用户1");
        SysRole r1 = new SysRole();
        r1.setRoleName("角色1");
        //建立关联关系
        //配置用户到角色关系,可以对中间表中的数据进行维护 1- 1
        u1.getRoles().add(r1);
        //配置角色到用户关系,可以对中间表中的数据进行维护 1- 1
        r1.getUsers().add(u1);
        //保存
        roleDao.save(r1);
        userDao.save(u1);
    }

    /*测试级联添加:保存一个用户的同时,保存用户的关联角色
    *
    * */
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testCasCadeAdd() {
        //创建对象
        SysUser u1 = new SysUser();
        u1.setUserName("用户2");
        SysRole r1 = new SysRole();
        r1.setRoleName("角色3");
        //建立关联关系
        //配置用户到角色关系,可以对中间表中的数据进行维护 1- 1
        u1.getRoles().add(r1);
        //配置角色到用户关系,可以对中间表中的数据进行维护 1- 1
        r1.getUsers().add(u1);
        //保存
        userDao.save(u1);
    }

    /*级联删除:删除id为2的用户同时删除他的关联对象*/
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testCasCadeRemove() {
        //1. 查询2号用户
        SysUser user = userDao.findOne(2l);
        //2. 删除用户
        userDao.delete(user);
    }

}
iii.多表的查询
代码语言:javascript
复制
    1.对象导航查询
        查询一个对象的同时,通过此对象查询他的关联对象

        案例:客户和联系人

        从一方查询多方
            * 默认:使用延迟加载(****)

        从多方查询一方
            * 默认:使用立即加载
对象导航查询测试

ObjectQueryTest.java

代码语言:javascript
复制
package cn.kt.test;/*
 *Created by tao on 2020-05-06.
 */

import cn.kt.dao.CustomerDao;
import cn.kt.dao.LinkManDao;
import cn.kt.domain.Customer;
import cn.kt.domain.LinkMan;
import org.hibernate.event.spi.SaveOrUpdateEvent;
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 org.springframework.transaction.annotation.Transactional;

import java.util.Set;

@RunWith(SpringJUnit4ClassRunner.class)  //声明单元测试
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ObjectQueryTest {
    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkManDao linkManDao;

    /*测试对象导航查询:查询一个对象的时候,通过此对象查询所有的关联对象
    * 默认使用的是延迟加载的形式查询的
        调用get方法并不会立即发送查询,而是在使用关联对象的时候才会差和讯
        延迟加载!
      修改配置,将延迟加载改为立即加载
        fetch,需要配置到多表映射关系的注解上
    * */
    @Test
    @Transactional  //解决java代码当中的 np session的问题
    public void testQuery1() {
        //查询id为1的对象
        Customer customer = customerDao.findOne(1l);
        //对象导航查询,此客户下的所有联系人
        Set<LinkMan> linkmans = customer.getLinkmans();
        for (LinkMan linkman : linkmans) {
            System.out.println(linkman);
        }
    }

    /*
     * 从联系人导航查询所属客户
     *  默认:立即加载
     * */
    @Test
    @Transactional  //解决java代码当中的 np session的问题
    public void testQuery2() {
        //查询id为1的对象
        LinkMan linkMan = linkManDao.findOne((long) 1);
        //对象导航查询所属客户
        Customer customer = linkMan.getCustomer();
        System.out.println(customer);
    }
}

总结:SpringDataJpa的使用方法

  1. 根据主键单表的CRUD
  2. 在接口使用@Query注解配置Jpql的灵活CRUD
  3. 在接口使用@Query注解配置Sql,nativeQuery = true的灵活CRUD
  4. 使用方法名的约定的方法进行查询 findBy +属性名+ "查询方式"+ "多条件的连接符(and|or)" +属性名+"查询方式"
  5. 给定条件不固定的时候,使用Specifications动态查询
  6. 一对多操作,在实体类里面配置一对多的关系映射
  7. 多对多操作,在实体类里面配置多对多的关系映射
  8. 对象导航查询测试 主体对象查询所有的关联对象 关联对象查询所属的主体对象
  9. 多表查询的级联操作
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Specifications动态查询
  • 多表之间的关系和操作
    • 多表之间的关系和操作多表的操作步骤
      • 完成多表操作
        • 映射的注解说明
        • i.一对多操作
        • ii.多对多操作
        • iii.多表的查询
    • 总结:SpringDataJpa的使用方法
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档