从零开始 Spring Boot 67:JPA 中的惰性元素

news2024/9/20 18:26:30

从零开始 Spring Boot 67:JPA 中的惰性元素

spring boot

图源:简书 (jianshu.com)

惰性加载带来的问题

在实体类之间建立关系时,可以选择“惰性加载”,比如:

@Entity
public class Student {
	// ...
    @OneToMany(mappedBy = "student",
            cascade = CascadeType.ALL,
            fetch = FetchType.LAZY)
    @Builder.Default
    private List<Email> emails = new ArrayList<>();
	// ...
}

@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"account", "domain"}))
public class Email {
	// ...
    @Setter
    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;
}

@OneToManyfetch属性可以选择FetchType.LAZYFetchType.EAGER,前者是惰性加载,后者是急切加载。如果是惰性加载,JPA 从数据库中加载Student实例时,不会立即加载关联的emails属性。而是直到真正使用emails属性时才会再查询并加载数据。

这样虽然可以避免不必要的关联查询,但同时也会产生另一个问题——获取到的关联数据是否有效?

为了避免这个问题,JPA 要求使用惰性加载时,相关数据的延迟加载与之前的实体数据加载在同一个事务下,否则就无法保证数据一致性。如果不这样做,就会产生异常。

比如下面这个示例,为Student创建服务层,并提供一个根据学生姓名查询学生实体实例的方法:

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
public class StudentService {
    @Autowired
    private StudentRepository studentRepository;

    public Student findStudentByName(String name) {
        return studentRepository.findOne(Example.of(Student.builder()
                .name(name)
                .build())).get();
    }
    // ...
}

调用示例:

var student = studentService.findStudentByName("icexmoon");
Assertions.assertEquals("icexmoon", student.getName());
Assertions.assertThrows(LazyInitializationException.class, () -> {
    student.getEmails().size();
});

因为调用示例中并没有使用事务,所以调用student.getEmails().size()时会产生一个LazyInitializationException异常。

要解决这个问题,最简单的是将关联集合的加载方式修改为FetchType.EAGER,但有时候我们可能不希望这么做,此时有一些其他方式可供我们选择。

使用 JPQL

可以直接使用 JPQL 进行关联查询,同时加载关联的数据:

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
public class StudentService {
    @Autowired
    private SessionFactory sessionFactory;
    
    public Student findStudentByName2(String name) {
        var session = sessionFactory.openSession();
        Student student = session.createQuery("select s from Student s join fetch s.emails where s.name=:name", Student.class)
            .setParameter("name", name)
            .getSingleResult();
        session.close();
        return student;
    }
}

SQL 日志:

select s1_0.id,e1_0.student_id,e1_0.id,e1_0.account,e1_0.domain,s1_0.name from student s1_0 join email e1_0 on s1_0.id=e1_0.student_id where s1_0.name=?
binding parameter [1] as [VARCHAR] - [icexmoon]

使用实体图

可以用实体图(Entity Graph)指定在 JPA 查询时需要加载的属性:

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
public class StudentService {
    @Autowired
    private SessionFactory sessionFactory;
	// ...
    public Student findStudentByName3(String name) {
        long id = this.findStudentByName("icexmoon").getId();
        var session = sessionFactory.openSession();
        RootGraph<Student> entityGraph = session.createEntityGraph(Student.class);
        entityGraph.addAttributeNodes("name", "emails");
        Map<String, Object> properties = new HashMap<>();
        properties.put("javax.persistence.fetchgraph", entityGraph);
        return session.find(Student.class, id, properties);
    }
}

可以阅读这篇文章了解实体图的更多信息。

使用事务

正如前面所说的,如果在延迟加载数据时能够在同一个事务中,也就不会出现类似的问题:

@Test
@Transactional
void test4(){
    var student = studentService.findStudentByName("icexmoon");
    Assertions.assertEquals("icexmoon", student.getName());
    Assertions.assertEquals(2, student.getEmails().size());
}

The End,谢谢阅读。

参考资料

  • Working with Lazy Element Collections in JPA | Baeldung

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/733664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot,vue网上订餐系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术 &#xff1a;VueElementUI 服务端技术&#xff1a;springbootmybatisredis 本系统分用户前台和管理后台两部分&#xff0c;项…

【Kafka】Kafka的Broker概述

【Kafka】Kafka的Broker概述 文章目录 【Kafka】Kafka的Broker概述1. Broker的工作流程1.1 Zookeeper存储的Kafka信息1.2 Broker 总体工作流程1.3 Broker重要参数 2. 节点服役和退役2.1 服役新节点2.2 退役旧节点 3. Kafka副本3.1 副本信息3.2 Leader选举流程3.3 Leader 和 Fol…

【成都】EFDC建模方法、SWAT模型高阶研修

EFDC建模方法及在地表水环境评价、水源地划分、排污口论证应用 为了定量地描述地表水环境质量与污染排放之间的动态关系&#xff0c;EFDC、MIKE、Delft3D、Qual2K等数值模型被广泛应用在环境、水务、海洋等多个领域。Environmental Fluid Dynamics Code&#xff08;EFDC&#…

[NISACTF 2022]checkin

[NISACTF 2022]checkin 直接给了源码&#xff0c;乍一看非常的简单&#xff0c;但是这题有坑。其实看注释颜色不一样&#xff0c;也能发现不对劲了。 贴一个payload&#xff0c;?ahahahahajitanglailo&%E2%80%AE%E2%81%A6Ugeiwo%E2%81%A9%E2%81%A6cuishiyuan%E2%80%AE%E2…

ARM异常处理详解

前言&#xff1a; 学习一门处理器最重要的就是掌握该处理器的指令集和异常处理。 异常概念&#xff1a; 处理器在正常执行程序时可能会遇到一些不正常的事件发生&#xff0c;这时处理器就要将当前的程序暂停下来转去处理这个异常的事件&#xff0c;异常处理后再返回到被异常打…

需求分析引言:架构漫谈(五)架构师成长之路

我研发领域也从事了一些年&#xff0c;期间也做过一些架构设计工作&#xff0c;包括C#单体转型为Java微服务、Python单体转型为Java微服务等&#xff0c; 也尝试着从自己的经验角度&#xff0c;来汇总一些知识点&#xff0c;同时描述一下如何成长为一个合格的软件架构师&#x…

权限管理系统后端实现1-SpringSecurity执行原理概述

spring security的简单原理&#xff1a; SpringSecurity有很多很多的拦截器&#xff0c;在执行流程里面主要有两个核心的拦截器 1&#xff0c;登陆验证拦截器AuthenticationProcessingFilter 2&#xff0c;资源管理拦截器AbstractSecurityInterceptor 但拦截器里面的实现需要…

IDEA+Spring Boot + MyBatis + Layui+Mysql垃圾回收管理系统源码

IDEASpring Boot MyBatis LayuiMysql垃圾回收管理系统源码 一、系统介绍1.环境配置 二、系统展示1. 管理员登录2.垃圾回收管理3.添加需要回收的垃圾4.垃圾去向管理5.申请需要打包运出的垃圾6.系统公告管理7.个人信息管理8.修改密码 三、部分代码UserMapper.javaUserControlle…

Python的网络爬虫框架-网络爬虫常用框架

Python的网络爬虫框架-网络爬虫常用框架 一、前言二、引言三、Scrapy 爬虫框架四、Crawley 爬虫框架五、PySpider 爬虫框架 一、前言 个人主页: ζ小菜鸡大家好我是ζ小菜鸡&#xff0c;让我们一起来了解Python的网络爬虫框架-网络爬虫常用框架如果文章对你有帮助、欢迎关注、点…

Redis缓存同步1-策略介绍

缓存数据同步策略示意图 在大多数情况下&#xff0c;我们通过浏览器查询到的数据都是缓存数据&#xff0c;如果缓存数据与数据库的数据存在较大差异的话&#xff0c;可能会产生比较严重的后果的。所以&#xff0c;我们应该也必须保证数据库数据、缓存数据的一致性&#xff0c;…

基于simulink使用颜色识别来进行道路跟踪(附源码)

一、前言 此示例演示如何使用颜色信息来检测和跟踪在可能不存在车道标记的主要住宅环境中设置的道路边缘。基于颜色的跟踪示例说明了如何使用色彩空间转换块、霍夫变换块和卡尔曼滤波器块来检测和跟踪使用色调和饱和度的信息。 二、模型 下图显示了基于颜色的道路跟踪模型&a…

MATLAB的num2str,把循环变量作为字符串的内容

MATLAB的num2str&#xff0c;把循环变量作为字符串的内容 输入代码&#xff1a; i 2; abc [sdfg,num2str(i),dsfg]运行结果&#xff1a; 解析&#xff1a; MATLAB里面的[ ]是会把元素组合的意思 现在有&#xff1a; a1 3; a2 4; a3 5; 然后我想通过for循环&#xff0c;循…

mac与pd虚拟机之间不能粘贴文字或粘贴文件

首先确保共享打开&#xff1a; 然后检查虚拟机的Parallels Tools是否正常 一个简单的判断方式就是&#xff0c;退出虚拟机全屏之后&#xff0c;如果能够正常进入融合模式&#xff0c;那么Parallels Tools可用&#xff0c;否则就要排查问题 检查Parallels Tools是否随系统正常启…

C++11 | 智能指针

智能指针 前面的文章中我们介绍了C中的异常有关的知识点&#xff0c;同时在其中我们遇到了有关内存方面的问题&#xff0c;如下所示&#xff1a; int div() {int a, b;cin >> a >> b;if (b 0)throw invalid_argument("除0错误");return a / b; } void…

数据结构算法题——链表

leetcode-2.两数之和 leetcode-2.两数之和 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数…

猿人学做题笔记

简单记录一下做题的思路步骤 1、第一题说的是无混淆加密&#xff08;简单&#xff09;&#xff1a; 刚开始观察请求&#xff0c;发现链接和请求携带的参数都没有什么异常&#xff0c;然后直接请求会拿不到数据&#xff0c;于是仔细看了一下请求包&#xff0c;发现请求头里面有…

03-Vue基础语法之指令语法与条件渲染

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大一在校生&#xff0c;web前端开发专业 &#x1f921; 个人主页&#xff1a;python学不会123 &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习…

【GaussDB(DWS)】数据分布式存储-三种类型的表

toc 一、环境说明 华为数据仓库服务DWS&#xff0c;集群版本8.1.3.320集群拓扑结构&#xff1a; 二、数据分布式方式 DWS采用水平分表的方式&#xff0c;将业务数据表的元组打散存储到各个节点内。这样带来的好处在于&#xff0c;查询中通过查询条件过滤不必要的数据&#…

[工业互联-18]:常见EtherCAT主站方案:SOEM的Windows/Linux解决方案

目录 第1章 SOEM 简介 第2章 SOEM创建EtherCAT主站 2.1 支持Linux和Windows操作系统 2.2 SOEM创建EtherCAT主站的步骤 第3章 QT添加SOEM主站 第1章 SOEM 简介 SOEM (Simple Open EtherCAT Master) 是一种开源的EtherCAT主站协议栈。 EtherCAT&#xff08;Ethernet for C…

飞轮储能系统的建模与MATLAB仿真(永磁同步电机作为飞轮驱动电机)

简介 飞轮储能系统由于其高储能密度、高效率、轻污染的优点而越来越受到重视。飞轮储能系统以高速旋转的飞轮为依托&#xff0c;通过电力电子设备实现电能与动能的相互转化&#xff0c;从而在负载调峰、功率平抑、不间断电源等多领域都有很好的应用表现。 本文选用永磁同步电机…