🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 简介 **Hibernate的一级缓存就是指session缓存, 默认打开** ~~~ private transient ActionQueue actionQueue; private transient StatefulPersistenceContext persistenceContext; ~~~ actionQueue它是一个行列队列,它主要记录crud操作的相关信息 persistenceContext它是持久化上下文,它其实是真正缓存。 在session中定义了一系列的集合来存储数据,它们构成session缓存。 只要session没有关闭,它就会一直存在。 当我们通过hibernate中的session提供的一些API例如 `save get update`等进行操作时,就会将持久化对象保存到session中,当下一次在去查询缓存中具有的对象(OID值来判断), 就不会去从数据库查询,而是直接从缓存中获取。 **Hibernate的一级缓存存在的目的就是为了减少对数据库访问。** **在hibernate中还有一个二级缓存, 使用范围是整个项目的,它是SessionFactory级别缓存。** # 一级缓存 ## 简介 Session缓存是一块内存空间,用来存放相互管理的java对象, 在使用 Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行査找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库; 如果没有找到相同OID值的对象,则会去数据库中査找相应数据。 当从数据库中査询到所需数据时,该数据信息也会放置到一级缓存中。 Hibernate的一级缓存的作用就是减少对数据库的访问次数。 在 Session接口的实现中包含一系列的Java集合,这些Java集合构成了 Session缓存。 只要session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。固一级缓存也被称为是 ession基本的缓存。 **Hibernate的一级缓存有如下特点:** 当应用程序调用 Session接口的 `save()、 update()、 saveOrUpdate`时,如果 Session缓存中没 有相应的对象, Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存 中去。 当调用 Session接口的 load()、get()方法,以及 Query接口的 list()、 iterator()方法时,会判 断缓存中是否存在该对象,有则返回,不会査询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。 当调用 Session的 close()方法时, Session缓存会被清空。 **演示一级缓存的存在** ~~~ //查询id=1的customer对象,如果查询到,会将c存储到一级缓存中 Customer c = session.get(Customer.class, 1); //会从一级缓冲中查询,而不会从数据库查 Customer c2 = session.get(Customer.class, 1); ~~~ **持久化对象具有自动更新数据库的能力** ~~~ //查询id=1的customer对象,如果查询到,会将c存储到一级缓存中 Customer c = session.get(Customer.class, 1); //操作持久化对象来修改属性 c.setName("tom"); ~~~ **为什么持久化对象具有自动更新数据库的能力?** Hibernate向一级缓存放入数据时,同时复制一份数据放入到 Hibernate快照中, **当使用commit方法提交事务时,同时会清理 Session的一级缓存,** 这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行 update语句,将缓存的内容同步到数据库,并更新快照; 如果一致,则不执行 update语句。 Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致 ![](https://img.kancloud.cn/13/a3/13a3c148955eeba01753dee03be7448c_1113x507.png) ## 一级缓存常用API 一级缓存特点: 1. 当我们通过session的save,update saveOrupdate进行操作时,如果一级缓存中没有对象,会将这些对象从数据库中查询到,存储到一级缓存。 2. 当我们通过session的load,get,Query的list等方法进行操作时,会先判断一级缓存中是否存在,如果没有才会从数据库获取,并且将查询的数据存储到一级缓存中。 3. 当调用session的close方法时,session缓存清空。 clear: 清空一级缓存. evict: 清空一级缓存中指定的一个对象。 **refresh: 重新查询数据库,用数据库中信息来更新一级缓存与快照** ~~~ List<Customer> list = session.createQuery("from Customer").list(); //会存储数据到一级缓存 session.clear(); //清空一级缓存 Customer c = session.get(Customer.class, 1); //会先从session一级缓存中获取,才会从数据库获取 session.evict(c); //从一级缓存中删除一个指定的对象 Customer cc = session.get(Customer.class, 1); cc.setName("kkk"); session.refresh(cc); //重新查询数据库,用数据库中信息来更新一级缓存与快照 ~~~ 一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理, 但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例 如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear. # Hibernate常用API-Session补充 ## update udpate操作它主要是针对于脱管对象,持久对象具有自动更新能力。 问题1:如果我们直接操作的对象是一个脱管对象,执行update会出现什么情况? Update操作时,如果对象是一个脱管对象,可以操作,它会将脱管对象转换成持久对象在操作 如果在session中出现相同的oid两个对象,会产生异常 ~~~ org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already ~~~ 问题2: 脱管对象的oid如果在数据表中不存在,会报异常? ~~~ org. hibernate. StaleStateException: Batch update returned unexpected row count from update [o]: actual row at org. hibernate jdbc Expectations$Basi cExpectation checkBatched (Expectations. java 67) ~~~ 所以:在操作中,建议我们通过持久化对象来直接修改其操作。 ## saveOrUpdate 如果对象是一个瞬时对象 --------执行save操作 如果对象是一个脱管对象---------执行update 如果是一个持久对象-------直接返回 ## delete 删除一个脱管对象,与session关联,在删除 注意:如果执行delete操作,先删除一级缓存,在删除数据库中的数据