当前位置:网站首页>Hibernate 的 Session 缓存相关操作
Hibernate 的 Session 缓存相关操作
2022-08-11 07:05:00 【血莲丹】
简介
Session 是 Hibernate 中最重要的接口,它提供了基本的保存、更新、删除和加载方法,是加载而不是查询,将对象加载到 session 缓存中。而查询是通过 Query 和 Criteria 两个对象来做的,但是也是通过 session 对象创建的,因此 session 很重要,是 Hibernate 的核心。
Session 缓存
先来看下 session 的缓存。再 Mybatis 中有一级二级缓存,同样的,Hibernate 也有。
先来加载两次相同的记录。
@Test
public void test2() {
SessionFactory sessionFactory;
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
News news1 = (News) session.get(News.class, 1);
System.out.println(news1);
News news2 = (News) session.get(News.class, 1);
System.out.println(news2);
transaction.commit();
session.close();
sessionFactory.close();
}
查看日志:
这就是基于 session 的一级缓存。除了我们创建的 news 变量引用这内存中的对象,session 缓存中也持有一份对象。当再次查询该对象时,会先去 session 缓存中查询有没有,有的话让新引用指向缓存中的对象。二级对象后面再说。
操作 session 缓存
session 操作缓存主要有如下的方法。他们之间的关系如下图所示。
flush() 方法
在讲 flush 方法之前,先对测试类进行一下改造,不然每次都要打那么多固定的代码,利用 JUnit 的生命周期方法能有效的减少冗余。
package com.zxb.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class HibernateTest2 {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init() {
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@Test
public void test() {
}
@After
public void destroy() {
transaction.commit();
session.close();
sessionFactory.close();
}
}
注:以后所有代码都基于上述代码结构。
现在来看如下的代码:
@Test
public void test() {
News news = (News) session.get(News.class, 1);
news.setTitle("Java");
}
执行上述代码前,先看下数据库中的记录。
此时再来执行上述代码。
可以看到,除了发送 SELECT 语句之外,还发送了 UPDATE 语句。数据库中的记录也发生了更改,这是为什么?
因为在 session 的 commit() 方法中,在调用事务的 commit() 方法前,先调用了 flush() 方法,然后再去 commit 事务的。
这个 flush() 方法的作用就是使表中的记录和 session 缓存中的记录保持一致,如果不一致,就会发送 SQL 去修改表中的记录。但是 单一的调用 flush() 方法是不会修改表中记录的,因为没有提交事务。
flush() 方法是让数据库表中的记录和 session 缓存中的对象保持一致,缓存中的对象是爷。
也可以打断点看看,当执行到 session.commit() 后才会发送 SQL。
但是除了显示的调用 session.flush() 方法和提交事务之外,还有如下场景也会在方法内部调用 flush() 方法。
1、 执行 HQL 或者 QBC 查询时,要求查询的对象必须是最新的状态,因此会先 flush() 一下,让数据库表中记录保持最新。
@Test
public void test3() {
News news = (News) session.get(News.class, 1);
// 在 QBC 查询前将缓存中记录修改
news.setAuthor("oracle");
Criteria criteria = session.createCriteria(News.class);
News news2 = (News) criteria.add(Restrictions.eq("id", 1)).uniqueResult();
System.out.println(news2);
}
可以在输出这行打个断点,此时查看控制台,发现已经调用 flush() 方法,发送了 UPDATE 语句,而不是在 commit 时调用。
2、 如果数据库表中的记录使用 native 生成器生成 OID(Object ID),那么当调用 session 的 save() 方法时内部也会调用 flush() 方法,立即发送 INSERT 语句向数据库插入该实体,因为只有这样 Hibernate 才能拿到记录的 ID,后面才能对该记录进行操作。所以说对象 ID 很重要,实体类中一定要有 ID 字段。
@Test
public void test4() {
News news = new News("C++", "ZXB", new Date());
session.save(news);
System.out.println("save...");
}
可以在输出语句这里打个断点,查看控制台会发现发送了一条插入语句,让数据库中和缓存中保持一致。这里也是调用 save() 方法时就调用了 flush() 方法,并非在 commit 才调用。
小结:
- flush() :根据缓存中的对象属性变化来同步更新数据库。
- 默认情况下,Session 在以下时间点 flush 缓存
– 显示调用 flush() 方法。
– 事务提交时,先调用 flush() 方法,再提交事务。
– 执行 HQL、QBC 查询时,如果缓存中的对象发生了变化,会先 flush(),保证查询的结果和缓存中的对象保持一致。
– 当对象使用 native 策略生成主键时,调用 session.save() 方法时,会立即 flush(),发送一条 INSERT 语句,使得数据库表中和缓存一致。 - commit() 和 flush() 方法的区别:flush() 方法会执行一系列 sql,但是不会提交事务。commit() 方法内部会先调用 flush() 方法,随后再提交事务。
refresh() 方法
根据 session 缓存的图示来看,refresh() 方法箭头是由数据库指向 session 缓存,所以也能猜到,refresh() 方法就是让缓存中的对象和数据库中的记录保持一致。
refresh() 方法是 session 缓存中的对象和数据库表中的记录保持一致,数据库表中的记录是爷。
举个例子:
@Test
public void test5() {
News news = (News) session.get(News.class,1);
System.out.println(news); // 断点
session.refresh(news);
System.out.println(news);
}
上述代码在第一次输出 news 时打个断点,当程序执行到断点处,我们手动修改数据库表中的记录,然后执行 refresh,看看第二次输出的 news 和第一次是否一致。
通过控制台的输出发现,两次打印结果是一致的,但是的确是发送了两次 SQL,这是 refresh 起效果了,不然有缓存,只会发送一次。这其实和 MySQL 的隔离级别有关,默认是可重复读,如果想要看到效果,可以在 hibernate.cfg.xml 中修改隔离级别。
<!-- 修改 Hibernate 的事务隔离级别,1,2,4,8 分别从低到高对应四种隔离界别 -->
<property name="hibernate.connection.isolation">2</property>
修改过后,再去执行,就能看到效果了。
clear() 方法
clear 方法就是清除 session 中的缓存,这个没啥好说的。
@Test
public void test6() {
News news1 = (News) session.get(News.class, 1);
session.clear();
News news2 = (News) session.get(News.class, 1);
}
此时发送两条查询语句,因为缓存已被清空。
边栏推荐
- 1002 Write the number (20 points)
- 1061 判断题 (15 分)
- [Recommender System]: Overview of Collaborative Filtering and Content-Based Filtering
- 1076 Wifi Password (15 points)
- tf.reduce_mean()与tf.reduce_sum()
- 详述MIMIC 的ICU患者检测时间信息表(十六)
- 从苹果、SpaceX等高科技企业的产品发布会看企业产品战略和敏捷开发的关系
- 2022-08-10 mysql/stonedb-slow SQL-Q16-time-consuming tracking
- JUC并发编程
- 梅科尔工作室——BP神经网络
猜你喜欢
1091 N-自守数 (15 分)
【Pytorch】nn.Linear,nn.Conv
【LeetCode每日一题】——682.棒球比赛
1.2 - error sources
Tensorflow中使用tf.argmax返回张量沿指定维度最大值的索引
1036 Programming with Obama (15 points)
Find the latest staff salary and the last staff salary changes
The growth path of a 40W test engineer with an annual salary, which stage are you in?
【LaTex-错误和异常】\verb ended by end of line.原因是因为闭合边界符没有在\verb命令所属行中出现;\verb命令的正确和错误用法、verbatim环境的用法
The softmax function is used in TF;
随机推荐
matplotlib
Service的两种启动方式与区别
break pad源码编译--参考大佬博客的总结
DDR4内存条电路设计
1046 punches (15 points)
1056 组合数的和 (15 分)
Square, multi-power, square root calculation in Tf
Depth (relay supervision)
国密规范 SM2 SM3 SM4
Four operations in TF
Tidb二进制集群搭建
2022-08-10 Group 4 Self-cultivation class study notes (every day)
梅科尔工作室——BP神经网络
How Unity handles C# under the hood
Implementation of FIR filter based on FPGA (5) - FPGA code implementation of parallel structure FIR filter
无服务器+域名也能搭建个人博客?真的,而且很快
There may be fields that cannot be serialized in the abnormal object of cdc and sqlserver. Is there anyone who can understand it? Help me to answer
Pico neo3 Unity打包设置
Taobao product details API interface
tf.cast(),reduce_min(),reduce_max()