4、JPA 一级缓存-延迟加载-对象状态

本文详细介绍了JPA中的一级缓存机制,包括其工作原理、缓存清空方法以及在多查询场景下的行为。同时,讨论了延迟加载和懒加载的区别,并展示了对象在不同状态下的行为。在案例分析中,解释了为何在未调用merge方法时,修改对象属性仍会导致更新SQL的执行,揭示了EntityManager内部快照区的作用。
摘要由CSDN通过智能技术生成

一级缓存

在EntityManager中存在一个一级缓存区域,称之为一级缓存;
每次查询时会把查询结果保存到一级缓存区中,下次再次查询时会根据主键ID判断是否缓存中有值,有则直接取出。
EntityManager 是线程不安全的,每次请求都会是一个全新的对象,一级缓存只存在于这个EntityManager中,缓存是有限的

缓存清空

在EntityManager提交事务或关闭之后,一级缓存会被清空。可以手动清空某一个缓存或所有缓存信息。

  1. detach 清除一级缓存中指定的对象
  2. clear 清除一级缓存中所有的对象

案例 多次查询时查看打印SQL

/**
     * 保存实体到数据库表
     */
    @Before
    public void save(){
        User u=new User();
        u.setName("jake");
        u.setBirthday(new Date());

        EntityManager entityManager = JpaUtil.getEntityManager();
        //开启事务
        entityManager.getTransaction().begin();
        //执行
        entityManager.persist(u);
        //关闭事务
        entityManager.getTransaction().commit();
        //归还连接
        entityManager.close();

    }

    @Test
    public void queryFromCache(){
        EntityManager entityManager = JpaUtil.getEntityManager();

        //1: 多次查询查看SQL打印只有1个,说明第二次查询直接从一级缓存获取数据
        User user = entityManager.find(User.class, 1L);
        User user1 = entityManager.find(User.class, 1L);
        System.out.println("user.getName() = " + user.getName());
        System.out.println("user.getName() = " + user1.getName());

        //2: 从另外一个EntityManager查询,也会打印SQL,一级缓存只存在于EntityManager中
        EntityManager otherEntity = JpaUtil.getEntityManager();
        User user2 = otherEntity.find(User.class, 1L);
        System.out.println("user.getName() = " + user2.getName());
        otherEntity.close();

        //3:手动清除缓存
        //清除缓存中某一个对象
//        entityManager.detach(user);
        //清除缓存中所有对象
        entityManager.clear();
        User user3 = entityManager.find(User.class, 1L);
        System.out.println("user.getName() = " + user3.getName());

        entityManager.close();

    }

延迟加载 懒加载

find()查询时,会立即执行SQL语句,不管后续是否用到这个查询结果了。
getReference查询时,不会立即执行SQL语句,只有真正使用到这个对象时,才会打印SQL语句到数据库查询。
懒加载的实现原理:JPA对查询结果对象进行了动态代理,重写所有Getter方法,当调用对象的Getter方法时,会触发SQL的执行

 @Test
    public void queryLazy(){
        EntityManager entityManager = JpaUtil.getEntityManager();
        //find 查询会立即执行SQL,不管这个user对象后续是否使用都会和数据库有一次查询
//        User user = entityManager.find(User.class, 1L);

        //getReference是个懒加载,后续如果没有地方使用,是不会去数据库查询的
        User reference = entityManager.getReference(User.class, 1L);
        System.out.println("reference = " + reference.getName());

        entityManager.close();
    }

对象状态

JPA对象状态分为4种,对对象的保存、修改、删除等操作都是对象状态的改变,不同的改变执行不同的SQL。从而把状态改变的操作转换成数据库的CRUD 操作

  1. 瞬时状态 Transisent 使用new 创建新对象,没有OID,一级缓存不存在
  2. 持久状态 Persistent 调用persist方法后,对象保存到数据库,一级缓存中同样有
  3. 游离状态 Detached 对象存在数据库中,但不在一级缓存中
  4. 删除状态 Removed 事务已提交,就会删除,持久状态和被删除之间的临界状态

| 状态 | 是否在一级缓存中 | 是否有OID
| 瞬时状态 | 否 | 否
| 持久状态 | 是 | 是
| 游离状态 | 否 | 是
| 删除状态 | 是 | 是

对象状态改变

  1. persist 将创建的对象或删除的对象变为Persistent状态,数据存到数据库和1级缓存中
  2. remove 删除持久状态对象
  3. merge 将游离实体转变为Persistent 状态,存到数据库
  4. 如果使用了事务管理,则事务在 commit/rollback 也会改变对象状态。对象状态变化或对象依赖的对象状态变化,都会导致对象的更新操作

在这里插入图片描述

案例分析 控制台为什么会有update 语句?

@Test
    public void changeState(){
        EntityManager entityManager = JpaUtil.getEntityManager();
        entityManager.getTransaction().begin();

        //查询对象后,只是修改属性,没有调用merge方法,name属性怎么会更新到数据库,有update SQL打印出来
        User user = entityManager.find(User.class, 1L);
        user.setName("haha");

        entityManager.getTransaction().commit();
        entityManager.close();
    }

为什么会出现update语句?

Hibernate: select user0_.id as id1_0_0_, user0_.birthday as birthday2_0_0_, user0_.name as name3_0_0_ from User user0_ where user0_.id=?
Hibernate: update User set birthday=?, name=? where id=?

分析:

将数据从数据库查询出来后,EntityManager的一级缓存存储一份,EntityManager的另一个快照区也存储了一份;在提交事务的时候,会清理一级缓存,此时会对2份数据对比是否一致,如果不一致会把缓存中的数据(脏数据)更新到数据库中,变成持久化状态。user.setName("haha");这个语句会把对象状态从持久状态变成游离状态,状态发生改变,需要把游离状态再次更新到数据库(持久状态)。这也就是为什么会出现Update语句的原因

EntityManager 快照区在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值