在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期
一级缓存是存在的,通过get()查询Customer对象,查询两次ID为1的Customer对象,控制台只发送了一条SQL,并且打印c1和c2,获得的地址是一样的,可以证明Session缓存是存在的
@Test
public void testSessionExist() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c1 = (Customer) session.get(Customer.class, 1);
System.out.println(c1);
Customer c2 = (Customer) session.get(Customer.class, 1);// 再次执行查询,直接使用一级缓存中数据
System.out.println(c2);
transaction.commit();
session.close();
}
Session缓存和快照的存储原理
@Test
public void testSession02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c = (Customer) session.get(Customer.class, 1); //persistent状态对象
c.setName("孙艺珍"); //修改一级缓存中的数据
//session.save(c); //不调用save()方法
transaction.commit();
session.close();
}
在没有调用save()情况下,程序依然更新了ID为1的Customer对象
代码层面关闭事物,在hibernte.cfg.xml中配置hibernate.connection.autocommit事物自动提交,但数据然仍没有被修改,只有flush()后才会去比较一级缓存和快照区数据是否一致,commit()中已经调用flush()了
@Test
public void testSession02() {
Session session = HibernateUtils.openSession();
Customer c = (Customer) session.get(Customer.class, 1); //persistent状态对象
c.setName("孙艺珍"); //修改一级缓存中的数据
session.flush();
//session.save(c); //不调用save()方法
session.close();
}
默认情况下 Session 在以下时间点刷出缓存:
- 当应用程序调用 Transaction 的 commit()方法的时, 该方法先刷出缓存(session.flush()),然后在向数据库提交事务(tx.commit())
- 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先刷出缓存,以保证查询结果能够反映持久化对象的最新状态
- 调用 Session 的 flush() 方法
一级缓存常见操作:
- flush 比较缓存数据和 快照数据是否一致,如果改变 ,将缓存数据更新到数据库,快照更新, 不会清除缓存数据
- clear 清除所有一级缓存数据,所有持久对象都会变为脱管对象
- evict 清除指定对象的一级缓存数据,被清除的对象,由持久变为脱管
- refresh 使用数据库中数据去覆盖缓存和快照的数据
一级缓存的FlushMode:
ALWAYS和AUTO的区别:当hibernate缓存中的对象被改动之后,会被标记为脏数据(即与数据库不同步了)。当 session设置为FlushMode.AUTO时,hibernate在进行查询的时候会判断缓存中的数据是否为脏数据,是则刷数据库,不是则不刷, 而always是直接刷新,不进行任何判断。很显然auto比always要高效得多