hibernate学习笔记03----一级缓存

来源:互联网 发布:电脑主机 知乎 编辑:程序博客网 时间:2024/06/05 01:00

Session的一级缓存

缓存作用:

将数据缓存到内存或者硬盘上,访问这些数据,直接从内存或硬盘加载数据,无需到数据表查询.好处:!降低数据库压力。

一级缓存的生命周期:

Session中对象集合(map),在Session创建时,对象集合(map)也就创建,缓存保存了Session对象数据,当Session销毁后,集合(map)销毁, 一级缓存释放 !

什么对象会被放入一级缓存?

只要是持久态对象,都会保存在一级缓存(与session关联的说法的本质,是将对象放入了一级缓存)



一级缓存的存在性

【示例】

通过多次查询同一个po对象数据,得到同一个对象,且第二次不再从数据库查询,证明一级缓存测存在。

//测试一级缓存的存在性@Test//测试方法:多次查询,是不是一个对象,看看有没有发出sqlpublic void testFirstCacheExist(){Session session = HibernateUtils.openSession();session.beginTransaction();//第一次查询:根据id查询//发生了:立即发出sql语句,查询数据,并将po放入一级缓存Customer customer =(Customer)session.get(Customer.class, 1);System.out.println(customer);//第二次查询//发生了:不发出sql,直接从一级缓存拿到数据(通过地址一样可以判断:是引用的同一个对象)Customer customer2 =(Customer)session.get(Customer.class, 1);System.out.println(customer2);session.getTransaction().commit();session.close();}

一级缓存的生命周期

一级缓存的生命周期就是session的生命周期,不能跨Session,可以说,一级缓存和session是共存亡的!

【示例】

使用两个不同Session来测试生命周期。(一级缓存和session共存亡)

//测试一级缓存的生命周期@Test//测试方法:关session看还能不能取到缓存的数据(看发不发sql)public void testFirstCachelifecycle(){Session session = HibernateUtils.openSession();session.beginTransaction();//从 数据库查询出数据:根据id,query对象,cretiea对象,都可以Customer customer = (Customer) session.get(Customer.class, 21);System.out.println(customer);//再次查询Customer customer2 = (Customer) session.get(Customer.class, 21);System.out.println(customer2);session.getTransaction().commit();session.close();//一级缓存随之销毁//-------------------------------------System.out.println("--------------------------------------");Session session2 = HibernateUtils.openSession();//一级缓存又重新诞生(是另外一个),但此时没数据,空的。session2.beginTransaction();//从 数据库查询出数据:根据id,query对象,cretiea对象,都可以Customer customer3 = (Customer) session2.get(Customer.class, 21);//将数据又放入一个新的一级缓存中System.out.println(customer3);//再次查询Customer customer4 = (Customer) session2.get(Customer.class, 21);//不发语句System.out.println(customer4);//地址相同session2.getTransaction().commit();session2.close();}


Session一级缓存的快照


如:

 

一句话:快照的作用就是用来更新数据的。

【注意】

1. 持久态对象原则:po对象尽量保持与数据库一一致。

2. 当一级缓存和快照不一致的时候,会先发出update语句,将一级缓存同步到数据库(发出update语句),然后当同步成功之后,再自动内部同步快照。保证三者的一致性。



一级缓存快照的能力

一级缓存的快照是由Hibernate来维护的,用户可以更改一级缓存(PO对象的属性值),无法手动更改快照!

快照的主要能力(作用)是:用来更新数据!当刷出缓存的时候,如果一级缓存和快照不一致,则更新数据库数据。


【示例】

通过改变查询出来的PO的属性值,来查看一级缓存的更改;通过提交事务,来使用快照更新数据。

@Test//测试一级缓存快照的能力(更新数据)public void testSnapShot(){Session session = HibernateUtils.openSession();session.beginTransaction();//立即发出sql,并且将将数据放入一级缓存(customer是一级缓存对象的引用)和快照Customer customer =(Customer)session.get(Customer.class, 1);System.out.println(customer);//改变一级缓存的数据customer.setName("Jack1");//快照可以局部更新(不用更新所有字段)//原理:将旧的值更新上去了。//customer.setAge(88);//等待提交(会自动flush刷新缓存)//在刷新缓存的时候,会自动对比一级缓存和快照是否一致,如果不一致,则发出update语句,更新数据到数据库,,并且同步到快照//不需要手动发出update方法动作session.getTransaction().commit();session.close();}


刷出缓存的时机

什么叫刷出缓存?

Session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步更新数据库,这一过程被成为刷出缓存(flush)。

 

什么情况下session会执行flush操作?

 

刷新缓存的三个时机:

事务提交commit():该方法先刷出缓存(session.flush()),然后再向数据库提交事务。

手动刷出flush():直接调用session.flush()

查询操作:当Query查询(getload除外,这两个会优先从一级缓存获取数据)时,如果缓存中持久化对象的属性已经发生了变化,(一级缓存和快照不一样了),则先刷出缓存,以保证查询结果能够反映出持久化对象的最新状态

 

【补充理解】:

关于Hibernate如何识别是同一一个对象?(持久态)

根据OID

问题:假如先查询出来一个对象oid1001,数据库主键也是1001,但其他字段的属性不一样,那么,再次查询数据库的数据出来的对象,和原来的对象是否是一个对象?

答案:是!


【示例】

三种方式刷出一级缓存

@Test//刷出一级缓存的时机public void testflushcacheTime(){Session session = HibernateUtils.openSession();session.beginTransaction();//前提:先将对象放入一级缓存,--持久态对象Customer customer =(Customer)session.get(Customer.class, 1);System.out.println(customer);//改变一级缓存对象的属性值!customer.setName("Jack13");customer.setAge(88);//等待Hibernate对一级缓存进行刷新//先用get//优先走一级缓存,只会从一级缓存取对象,不会去数据库校验,数据是否过期Customer customer11 =(Customer)session.get(Customer.class, 1);System.out.println(customer11);//query.list是也走一级缓存,但会校验,先得查询,然后flush一下,保证同步Customer customer12 =(Customer)session.createQuery("from Customer where id=1").uniqueResult();System.out.println(customer12);//显式的刷新session.flush();//刷出一级缓存,对比快照,发出update语句//隐式的刷新session.flush();session.getTransaction().commit();//flush和commit区别//flush作用是控制发出语句的,向数据库发sql的。//commit:本质:提交事务,只是,hierarnate隐式的flush了一下session.close();}

【提示】

flushcommit的区别:

flush是发语句的。对比快照

commit的是数据库层面的是否保存更改的数据(是否提交数据,是否持久化数据到数据库),不手动发出flush hibernatecommit之前自动先flush()


一级缓存的常用操作

一级缓存除了可以flush之外,还可以清除(clearevict)、重载(reflesh)。

 

l flush:刷出一级缓存

作用:当一级缓存发生变化时,即和快照不同时,刷出一级缓存,自动向数据库提交update语句

如果是Mysql数据库,开启事务后,当手动flush后,不手动commitHibernate不会自动commit

如果是Oracle数据库,开启事务后,当手动flush后,不手动commitHibernate自动commitoracles事务的提交:手动提交、正常关闭连接的时候也会隐式提交);


l clear:清除一级缓存

作用:清除一级缓存中的所有对象,这些对象被清除后,会从持久态对象变成脱管态.

【扩展理解】

持久态对象与session关联的另一层含义就是对象在一级缓存中存在。

l evict:清除一级缓存指定对象

作用:清除一级缓存中的指定对象,使对象变成脱管态的。

l reflesh:刷新一级缓存

作用:刷新一级缓存中指定的对象,即发出SQL语句,

将对象重新放入一级缓存,并试图将数据库的数据同步到一级缓存中(同时更新一级缓存和快照),一级缓存之前的如果有修改将被覆盖掉。flush有相反的感觉。


为什么要清除一级缓存:

大批量处理数据的时候,有些数据无需在一级缓存存在,或者已经处理完了,为了防止内存泄漏,一级缓存爆满,可以手动清除一级缓存的对象。




原创粉丝点击