文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringJPA联表查询之OneToOne源码详解

2023-05-18 05:07

关注

前言

前面几篇我们学习的都是单表查询,就是对一张表中的数据进行查询。而实际项目中,基本都会有多张表联合查询的情况,今天我们就来了解下JPA的联表查询是如做的。

源码

@OneToOne 注解实现一对一关系映射。比如用户跟车辆的关系(这里假设一个人只能有一辆车),一个用户只能对应一辆车,而一辆车同样只能对应一个用户。
老规矩,在实例之前,我们先看看源码:

public @interface OneToOne {
    Class targetEntity() default void.class;
    CascadeType[] cascade() default {};
    FetchType fetch() default EAGER;
    String mappedBy() default "";
    boolean orphanRemoval() default false;
}

注解属性

单向联表

我这里所说的单向联表就是只有一方添加注解;通俗讲就是我可以通过 user 获取到其 car 的信息,而不同通过 car 获取到其 user 的信息。

user 实体类

@Entity
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    private int age;
    @OneToOne
    @JoinColumn(name = "car_id")
    private Car car;
}

car 实体类

@Data
@Entity
public class Car {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
}

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

Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.age as age2_1_0_,
        user0_.car_id as car_id4_1_0_,
        user0_.name as name3_1_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=?

查询结果

Optional[User(id=1, name=lili, age=11, car=Car(id=1, name=苏A00001))]

从上面的 JPQL 语句我们可以发现,uer 表car 表 是通过left outer jion进行连接的。这样我们可以通过查询 user 信息来获取其使用的 car 信息。

双向联表

我们除了需要通过 user 信息来获取其 car 信息为,有时还需要通过 car 信息来获取其 user 信息。只要再在 car 的实体中添加 user 字段,并添加@OneToOne注解。(这里有一个堆栈溢出的问题需要注意一下,详情请见 JPA 错题集 第二个报错信息)

user 实体

@Entity
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    private int age;
    @OneToOne
    @JoinColumn(name = "car_id")
    @JsonIgnore
    private Car car;
}

car 实体

@Entity
@Data
public class Car {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    @OneToOne
    @JoinColumn(name = "user_id")
    @JsonIgnore
    private User user;
}

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

Hibernate: 
    select
        car0_.id as id1_0_0_,
        car0_.name as name2_0_0_,
        car0_.user_id as user_id3_0_0_,
        user1_.id as id1_2_1_,
        user1_.age as age2_2_1_,
        user1_.car_id as car_id4_2_1_,
        user1_.name as name3_2_1_,
        car2_.id as id1_0_2_,
        car2_.name as name2_0_2_,
        car2_.user_id as user_id3_0_2_ 
    from
        car car0_ 
    left outer join
        user user1_ 
            on car0_.user_id=user1_.id 
    left outer join
        car car2_ 
            on user1_.car_id=car2_.id 
    where
        car0_.id=?

查询结果

Optional[Car(id=1, name=苏A00001, user=com.example.sbjdemo.pojo.User@1c0775ea)] 用户信息可以通过后面的实体类获取

延迟加载(懒加载)

上面是 OneToOne 的情形,所以请求出来的数据也是比较有限的。试想一下,如果是 OneToMany,而我们只想获取 one 的信息,但是 many 的数据却跟着一起请求出来的,无论是从数据上还是性能上来讲,都是一种负担。那么,有没有一种方法,让我们能够只获取 one 的信息,而对于 many 可以动态获取呢?这时,我们想到了源码中一个 fetch 方法,他好像可以使用 LAZY 属性来控制数据懒加载。废话少说,上码。

user 实体

User 实体类上的 Car 属性中 @OneToOne 添加属性 fetch = FetchType.LAZY

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "car_id")
@JsonIgnore
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=?

查询结果:

Optional[com.example.sbjdemo.pojo.User@30c311e6] 通过控制台可以看出,只有一个用户查询的 sql,结果也就是一个 user 的实体类数据。那我们的 car 信息该如何查看呢?其实我们可以使用查询结果 resultget 我们所需要的数据,如下图所示:

查询完会发现,控制台又打印了一个 JPQL:

Hibernate: 
    select
        car0_.id as id1_0_0_,
        car0_.name as name2_0_0_,
        car0_.user_id as user_id3_0_0_,
        user1_.id as id1_2_1_,
        user1_.age as age2_2_1_,
        user1_.car_id as car_id4_2_1_,
        user1_.name as name3_2_1_ 
    from
        car car0_ 
    left outer join
        user user1_ 
            on car0_.user_id=user1_.id 
    where
        car0_.id=?

恍然大悟,原来还是通过 sql 去完成的。

最后结论

oneToOne 主要针对一对一的场景,他们双方都可以作为维护端或者被维护端,所以 mappedBy 这个属性可有可无。这也要是与其他三个映射关系不同的地方。

以上就是Spring JPA联表查询之OneToOne源码详解的详细内容,更多关于Spring JPA联表查询的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯