Spring JPA联表查询之注解属性详解

目录
  • 前言
  • 一、targetEntity
  • 二、cascade
    • 1、不定义
    • 2、CascadeType.PERSIST
    • 3、CascadeType.REMOVE
    • 4、CascadeType.REFRESH
    • 5、CascadeType.MERGE
    • 6、CascadeType.ALL
  • 三、fetch
    • FetchType.LAZY
    • FetchType.EAGER
  • 四、mappedBy
  • 五、orphanRemoval

前言

对于联表查询的四个注解 @OneToOne@OneToMany@ManyToOne@ManyToMany,他们有几个用得比较多的属性需要了解一下。

一、targetEntity

(可选)指定关联的实体类;默认为当前标注的实体类。

@JoinColumn(name = "car_id")
@OneToOne(fetch = FetchType.LAZY, targetEntity = Car.class)
private Car car;

二、cascade

(可选)当前类对象操作后级联对象的操作。默认为不级联任何操作。

1、不定义

只对作用的实体类有影响,对级联对象不会产生任何影响

2、CascadeType.PERSIST

级联新建。对父对象进行持久化,同时对子对象也相应的持久化。

user 实体类中关联的对象字段(级联对象)

@JoinColumn(name = "car_id")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JsonIgnore
private Car car;

service 层新建方法

@GetMapping("/save")
public User save(String name, Integer age, String carname) {
    User user = new User();
    user.setName(name);
    user.setAge(age);
    Car car = new Car();
    car.setName(carname);
    car.setUser(user);
    user.setCar(car);
    return userService.save(user);
}

执行请求 /user/save?name=lala&age=21&carname=苏M00002,控制台打印如下:

Hibernate:
    insert
    into
        user
        (age, car_id, name)
    values
        (?, ?, ?)
Hibernate:
    update
        car
    set
        name=?,
        user_id=?
    where
        id=?

如果有级联新建(保存)的需求,只能使用 CascadeType.PERSIST 或者 CascadeType.ALL,使用其他的操作会报错。

3、CascadeType.REMOVE

级联删除。删除数据库中的对应实体,同时删除对应的所有关联对象

user 实体类中关联的对象字段(级联对象)

@JoinColumn(name = "car_id")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@JsonIgnore
private Car car;

service 层删除方法

/**
 * 通过id进行删除数据
 * @param id
 */
@GetMapping("/deleteById")
public void deleteById(Integer id){
    userService.deleteById(id);
}

执行请求 /user/deleteById?id=17,控制台打印如下:

Hibernate:
    select
        user0_.id as id1_2_0_,
        user0_.age as age2_2_0_,
        user0_.car_id as car_id4_2_0_,
        user0_.name as name3_2_0_
    from
        user user0_
    where
        user0_.id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [17]
Hibernate:
    select
        car0_.id as id1_0_0_,
        car0_.name as name2_0_0_,
        car0_.user_id as user_id3_0_0_
    from
        car car0_
    where
        car0_.id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [5]
Hibernate:
    update
        car
    set
        name=?,
        user_id=?
    where
        id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [苏M00001]
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [null]
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [INTEGER] - [5]
Hibernate:
    delete
    from
        user
    where
        id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [17]
Hibernate:
    delete
    from
        car
    where
        id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [5]

如果有级联删除的需求,只能使用 CascadeType.REMOVE 或者 CascadeType.ALL;使用其他的虽然不会报错,但是只会对作用对象进行删除,相关联的数据不会进行删除。

4、CascadeType.REFRESH

级联刷新。作用对象 refresh 的同时级联对象也进行 refresh。这里 refresh 方法是EntityManager 的方法,我们来看一下他的源码

/**
 * Refresh the state of the instance from the database,
 * overwriting changes made to the entity, if any.
 * @param entity  entity instance
 * @throws IllegalArgumentException if the instance is not
 *         an entity or the entity is not managed
 * @throws TransactionRequiredException if there is no
 *         transaction when invoked on a container-managed
 *         entity manager of type <code>PersistenceContextType.TRANSACTION</code>
 * @throws EntityNotFoundException if the entity no longer
 *         exists in the database
 */
public void refresh(Object entity);

最主要的是从数据库中刷新实例的状态,覆盖对实体所做的更改(如果有的话);通俗讲就是,只要没有做持久化的数据更改,就得不到我的认可。

5、CascadeType.MERGE

级联更新。

user 实体类中关联的对象字段(级联对象)

@JoinColumn(name = "car_id")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
@JsonIgnore
private Car car;

service 层更新方法

@GetMapping("/save")
    public User save(Integer id, String name, Integer age, Integer carid, String carname) {
        User user = new User();
        if (id != null) user.setId(id);
        user.setName(name);
        user.setAge(age);
        Car car = new Car();
        if (carid != null) car.setId(carid);
        car.setName(carname);
        car.setUser(user);
        user.setCar(car);
        return userService.save(user);
    }

执行请求/user/save?id=1&name=kiki&age=33&carid=1&carname=苏M00003,控制台打印如下:

Hibernate:
    select
        user0_.id as id1_2_1_,
        user0_.age as age2_2_1_,
        user0_.car_id as car_id4_2_1_,
        user0_.name as name3_2_1_,
        car1_.id as id1_0_0_,
        car1_.name as name2_0_0_,
        car1_.user_id as user_id3_0_0_
    from
        user user0_
    left outer join
        car car1_
            on user0_.car_id=car1_.id
    where
        user0_.id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
Hibernate:
    update
        car
    set
        name=?,
        user_id=?
    where
        id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [苏M00003]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [1]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [INTEGER] - [1]
Hibernate:
    update
        user
    set
        age=?,
        car_id=?,
        name=?
    where
        id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [33]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [1]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [kiki]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [INTEGER] - [1]

可以更新所有级联的对象,但是前提是要提供对象的 id,否则系统会认为你是新增。

6、CascadeType.ALL

表示同时选择 CascadeType.PERSISTCascadeType.REMOVECascadeType.REFRESH 和 CascadeType.MERGE。一般情况不会使用,因为 CascadeType.REMOVE 是个高危操作。

三、fetch

(可选)关联是否延迟加载(懒加载 FetchType.LAZY)或者立刻加载(FetchType.EAGER)。立刻加载是立刻获取关联的实体;延迟加载(懒加载)是表示关系类在被访问时才加载。

FetchType.LAZY

User 实体类上的 Car 属性中 @OneToOne 添加属性 fetch = FetchType.LAZY(这里有一个报错需要注意一下,详情请见 # Spring JPA 错题集 第一个信息)

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "car_id")
private Car car;

执行请求/user/findById?id=1,控制台打印如下:

Hibernate:
    select
        user0_.id as id1_2_0_,
        user0_.age as age2_2_0_,
        user0_.car_id as car_id4_2_0_,
        user0_.name as name3_2_0_
    from
        user user0_
    where
        user0_.id=?
[nio-7777-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
Hibernate:
    select
        car0_.id as id1_0_0_,
        car0_.name as name2_0_0_
    from
        car car0_
    where
        car0_.id=?
[nio-7777-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]

这里先挖一个坑,就是 JPA 在读取数据时 N+1 的问题。

FetchType.EAGER

再看看立刻加载的场景。
执行请求/user/findById?id=1,控制台打印如下:

Hibernate:
    select
        user0_.id as id1_2_0_,
        user0_.age as age2_2_0_,
        user0_.car_id as car_id4_2_0_,
        user0_.name as name3_2_0_,
        car1_.id as id1_0_1_,
        car1_.name as name2_0_1_
    from
        user user0_
    left outer join
        car car1_
            on user0_.car_id=car1_.id
    where
        user0_.id=?
[nio-7777-exec-2] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]

懒加载的时候(LAZY)只会将主体数据请求出来,对于级联数据需要我们主动 get,如下图所示:

而立刻加载的时候(EAGER)会将主体数据和所有级联数据请求出来,对于大数据的情况,系统可能会存在一定的压力,所以实际项目中,我们大多数情况下会使用 FetchType.LAZY

四、mappedBy

(可选)拥有关联关系的域,如果关系是单向的就不需要;如果是双向关系表,那么拥有关系的这一方有建立、解除和更新与另一方关系的能力,而另一方没有,只能被动管理,这个属性被定义在关系的被拥有方

五、orphanRemoval

(可选)是否将删除操作应用于具有已从关系中删除,并将删除操作级联到这些实体;默认为false。

以上就是Spring JPA联表查询之注解属性详解的详细内容,更多关于Spring JPA联表查询注解属性的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring JPA find单表查询方法示例详解

    目录 一.findById(ID id) 二.findAll() 三.findAllById(Iterable<ID> ids) 四.findAll(Sort sort) 单调排序 sort.by 源码 control层 五.findAll(Sort sort) 多参数排序 Sort by 源码 control 层 总结 一.findById(ID id) 通过id进行单条查询,先看看 findById(ID id) 的源码 @Override public Optional<T>

  • Spring JPA之find拓展方法示例详解

    目录 前言 一.单条件查询 1.精确查询(确定值,例如:=.is) 2.范围查询(一定范围,例如<.<=.>.>=.in.between) a)运算符 b)between c)in 3.模糊查询 a)findByNameLike b)findByNameStartingWith 二.多条件查询 三.关键字 最后总结: 前言 前两篇我们详细了解了 findById 和 findAll 以及 findAll 的分页查询,如果说JPA只有上面的两种查询功能,那就太low了,今天让我们再深

  • Spring JPA联表查询之OneToOne源码详解

    目录 前言 源码 注解属性 单向联表 user 实体类 car 实体类 查询结果 双向联表 user 实体 car 实体 查询结果 延迟加载(懒加载) user 实体 查询结果: 查询完会发现,控制台又打印了一个 JPQL: 最后结论 前言 前面几篇我们学习的都是单表查询,就是对一张表中的数据进行查询.而实际项目中,基本都会有多张表联合查询的情况,今天我们就来了解下JPA的联表查询是如做的. 源码 @OneToOne 注解实现一对一关系映射.比如用户跟车辆的关系(这里假设一个人只能有一辆车),一

  • Spring JPA之save方法示例详解

    目录 一.save(单条添加) 源码 service 层 control层 二.saveAll(批量添加) 源码 service control层 一.save(单条添加) 源码 @Transactional @Override public <S extends T> S save(S entity) { Assert.notNull(entity, "Entity must not be null."); if (entityInformation.isNew(enti

  • Spring JPA联表查询之OneToMany源码解析

    目录 前言 源码 单向联表 user 实体类 house 实体类 查询结果 双向联表 user 实体类 house 实体类 对象获取 前言 我们在实际项目中,除了会碰到一对一的情况,还有一对多的情况,比如一个用户可以有多辆车,而一辆车只能有一个用户等等,今天我们就来一起学习下 OneToMany(一对多). 源码 @OneToMany 注解实现一对多关系映射.比如用户跟房子的关系, 一个用户可以有好多房子,而一个房子只能一个用户.老规矩,实例之前先看看源码: public @interface

  • Spring JPA学习之delete方法示例详解

    目录 一.deleteById 和 delete deleteById(Id id)(通过id进行删除) delete(T entity)(通过实体对象进行删除) 实例 service 层 control层 二.deleteAllById 和 deleteAll 1.deleteAllById(Iterable<? extends ID> ids)(通过id进行批量删除) 2.deleteAll(Iterable<? extends T> entities)(通过实体对象进行批量删

  • Spring JPA find分页示例详解

    目录 前言 源码 一.单纯分页查询 查询结果 结论 二.排序分页查询 查询结果 三.方法整理 总结: 前言 在现实项目中,数据量一般都不小,如果一次性全部请求出来,肯定是影响性能,而且大量数据展示到页面上观感也不好.这时我们就需要用到分页,给定一个 pageSize,每次请求的数量就是 pageSize 的大小,这样既可以节约时间,又可以美化页面.Spring JPA 就为我们提供这样一个方法,准确来说是提供了一个对象用来约束数据按照分页的形式进行请求. 源码 findAll(Pageable

  • Java Mybatis框架多表操作与注解开发详解分析

    目录 一对一查询 多对多查询 Mybatis的注解开发 Mybatis的增删查改 MyBatis的注解实现复杂映射开发 一对一查询 一对一查询的模型 用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户. 一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户 一对一查询的语句 对应的sql语句: select * from orders o,user u where o.uid=u.id;查询的结果如下: 创建Order和User实体 创建OrderMapper接口 p

  • Mysql联表update数据的示例详解

    1.MySQL UPDATE JOIN语法 在MySQL中,可以在 UPDATE语句 中使用JOIN子句执行跨表更新.MySQL UPDATE JOIN的语法如下: UPDATE T1, T2, [INNER JOIN | LEFT JOIN] T1 ON T1.C1 = T2. C1 SET T1.C2 = T2.C2, T2.C3 = expr WHERE condition 更详细地看看MySQL UPDATE JOIN语法: 首先,在UPDATE子句之后,指定主表(T1)和希望主表连接表

  • Spring Data Jpa 中原生查询 REGEXP 的使用详解

    目录 Spring Data Jpa原生查询 REGEXP 的使用 spring data jpa 原生查询(查一个json中的某一字段) Spring Data Jpa原生查询 REGEXP 的使用 REGEXP 与like 有通用之处, 单 regexp 有更好的精确度,更加自由灵活 在jpa 中使用时 :其中 定位符 ^ 在jpa @query 注解中使用时需要加上引用号 e.g @Query(value = "select p.id as id from zt_products AS p

  • Spring Boot框架中的@Conditional注解示例详解

    目录 1. @Conditional 注解 2. Spring boot 扩展 1) @ConditionalOnClass和@ConditionalOnMissingClass注解 2) @ConditionalOnBean 和@ConditionalOnMissingBean注解 3) @ConditionalOnProperty注解 1. @Conditional 注解 @Conditional注解是Spring-context模块提供了一个注解,该注解的作用是可以根据一定的条件来使@Co

  • Spring Data Jpa多表查询返回自定义实体方式

    目录 SpringDataJpa多表查询返回自定义实体 Repository 好下面到单元测试 自定义实体 SpringDataJpa多表查询返回自定义VO的问题 下面是我的代码 下面是我的dao层,重点 SpringDataJpa多表查询返回自定义实体 比如来看一下这样的一条SQL语句,这是一个三张表的多表查询,显然在JPA中用一个实体类是接受不了这些参数的 select  t1.id as chapterId , t1.name as chapterName , t2.id as unitI

  • mongodb实现同库联表查询方法示例

    前言 最近在工作中遇到一个问题,需要对mongodb数据库进行联表查询操作,发现网上这方面的资料较少,无奈只能自己来实现了,下面话不多说了,来一起看看详细的介绍: 注意:这里只对同库联表查询做介绍,跨库联表查询可能在之后也会介绍(因为公司架构变动,之后可能会联表查询) 我用到的联表查询有两种,一种是mongoose的populate,一种是$lookup 一.populate populate是使用外键关联子表 例如现在有一张订单表结构(动态外键): var orderSchema = new

  • Spring Data JPA 简单查询--方法定义规则(详解)

    一.常用规则速查 1 And 并且 2 Or   或 3 Is,Equals 等于 4 Between   两者之间 5 LessThan 小于 6 LessThanEqual   小于等于 7 GreaterThan 大于 8 GreaterThanEqual   大于等于 9 After 之后(时间) > 10 Before 之前(时间) < 11 IsNull 等于Null 12 IsNotNull,NotNull 不等于Null 13 Like 模糊查询.查询件中需要自己加 % 14

  • MyBatis-Plus联表查询(Mybatis-Plus-Join)的功能实现

    目录 引入依赖 数据准备 修改Mapper 查询 分页查询 最后 mybatis-plus作为mybatis的增强工具,简化了开发中的数据库操作.一旦遇到left join或right join的左右连接,还是得老老实实的打开xml文件,手写上一大段的sql语句.今天总结一下一款叫做mybatis-plus-join的工具(后面就简称mpj了),可以用类似mybatis-plus中QueryWrapper的方式来进行联表查询. 引入依赖 首先在项目中引入引入依赖坐标,因为mpj中依赖较高版本my

  • 详解Yii2.0使用AR联表查询实例

    Yii2.0中使用联表查询有两种办法,第一种是查询构建器(Query Builder),第二种使用活动记录(Active Record),中文网对查询构建器讲的很详细,AR则说的很坑爹,下面贴出自己实践的方法,以供参考. 两个表 {{%article}} 和 {{%article_class}} {{%article}} .article_class关联{{%article_class}}.id 1.要使用AR做关联查询,首先在models {Article} 中创建关联: class Arti

随机推荐