缓存不止存在与程序中, 电脑硬件乃至于生活中都存在缓存
目的: 提高效率
比如 IO 流读写字节, 如果没有缓存, 读一字节写一字节, 效率低下
hibernate 中的一级缓存: 提高操作数据库的效率
示例:
抽取的工具类
- package utils;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.cfg.Configuration;
- public class HibernateUtils {
- private static SessionFactory sf;
- static {
- //1 创建, 调用空参构造
- Configuration conf = new Configuration().configure();
- //2 根据配置信息, 创建 SessionFactory 对象
- sf = conf.buildSessionFactory();
- }
- // 获得 session => 获得全新 session
- public static Session openSession() {
- //3 获得 session
- Session session = sf.openSession();
- return session;
- }
- // 获得 session => 获得与线程绑定的 session
- public static Session getCurrentSession() {
- //3 获得 session
- Session session = sf.getCurrentSession();
- return session;
- }
- }
- View Code
测试类:
示例 1:
- package cache;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- import org.junit.Test;
- import domain.Customer;
- import utils.HibernateUtils;
- // 测试一级缓存
- public class Demo {@Test
- // 证明一级缓存存在
- public void fun1() {
- //1 获得 session
- Session session = HibernateUtils.openSession();
- //2 控制事务
- Transaction tx = session.beginTransaction();
- //3 执行操作
- Customer c1 = session.get(Customer.class, 1l);
- Customer c2 = session.get(Customer.class, 1l);
- Customer c3 = session.get(Customer.class, 1l);
- Customer c4 = session.get(Customer.class, 1l);
- Customer c5 = session.get(Customer.class, 1l);
- System.out.println(c3 == c5); //true
- //4 提交事务. 关闭资源
- tx.commit();
- session.close(); // 游离 | 托管 状态, 有 id , 没有关联
- // 结果 (保证数据库中存在主键为 1 的数据):
- // 这里调用了五次方法, 但是只打印一次 SQL 语句
- }
- }
原理: 程序第一次调用 get 方法, hibernate 发送 SQL 语句查询数据库, 查询结果以 ResulySet 对象返回,
hibernate 再组装成 Customer(实体类对象), 存入 session 缓存对象, 对象返回给程序
第二次调用 get 方法, 会先从缓存中查看是否存在 id=1 的 Customer 对象, 如果有, 直接返回缓存中的对象
多次调用原理相同
明显地发现: 这里的缓存技术很好地提升了效率
示例 2:
- @Test
- //
- public void fun2() {
- //1 获得 session
- Session session = HibernateUtils.openSession();
- //2 控制事务
- Transaction tx = session.beginTransaction();
- //3 执行操作
- Customer c1 = session.get(Customer.class, 1l);
- c1.setCust_name("哈哈"); //4 提交事务. 关闭资源
- tx.commit();
- session.close(); // 游离 | 托管 状态, 有 id , 没有关联
- }
引入了快照的概念
原理:
上边的原理其实有省略, 数据库返回结果后, hibernate 组装的时候, 其实组装了两个对象,
一个放入缓存中, 一个放入快照, 返回给程序的是缓存对象, 程序第一次修改了缓存对象, 事务提交,
这时候 hibernate 比较缓存中的对象和快照, 如果有变化, 会同步到数据库中, 没有变化, 什么都不做
这里就提高了效率, 不会多次去数据库查询, 只需要比对缓存中的对象, 减少不必要地 SQL 查询语句
示例 3:
- @Test
- // 持久化状态对象其实就是放入 session 缓存中的对象
- public void fun3() {
- //1 获得 session
- Session session = HibernateUtils.openSession();
- //2 控制事务
- Transaction tx = session.beginTransaction();
- //3 执行操作
- Customer c1 = new Customer();
- c1.setCust_id(1l); // 托管 | 游离
- session.update(c1); //c1 被放入 session 缓存了
- Customer c2 = session.get(Customer.class, 1l);
- //4 提交事务. 关闭资源
- tx.commit();
- session.close(); // 游离 | 托管 状态, 有 id , 没有关联
- }
这段代码运行中, 打印 SQL 的 UPDATE 语句
原因: 缓存中不存在快照, c1 放入 session 缓存中对比快照时候必然不一致, 而 c2 这一句调用 get 方法后, 依照上边的原理, 才会运行 SQL 的 UPDATE 语句
所以, 这段代码中真正使 hibernate 发送 SQL 语句的是 c2 这一行
来源: http://www.bubuko.com/infodetail-2498764.html