Java三大框架之——Hibernate中的三种数据持久状态和缓存机制

Hibernate中的三种状态

    瞬时状态:刚创建的对象还没有被Session持久化、缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID。   

  持久状态:对象经过Session持久化操作,缓存中存在这个对象的数据为持久状态并且数据库中存在这个对象对应的数据为持久状态这个时候有OID

  游离状态:当Session关闭,缓存中不存在这个对象数据而数据库中有这个对象的数据并且有OID为游离状态。

  注:OID为了在系统中能够找到所需对象,我们需要为每一个对象分配一个唯一的表示号。在关系数据库中我们称之为关键字,而在对象术语中,则叫做对象标识

(Object identifier-OID).通常OID在内部都使用一个或多个大整数表示,而在应用程序中则提供一个完整的类为其他类提供获取、操作。

  Hibernate数据状态图:

    

需要注意的是:

  当对象的临时状态将变为持久化状态。当对象在持久化状态时,它一直位于 Session 的缓存中,对它的任何操作在事务提交时都将同步到数据库,因此,对一个已经持久的对象调用 save() 或 update() 方法是没有意义的。  

Student stu = new Strudnet();stu.setCarId(“200234567”);stu.setId(“100”);// 打开 Session, 开启事务//将stu对象持久化操作
session.save(stu);stu.setCardId(“20076548”);//再次对stu对象进行持久化操作
session.save(stu); // 无效

session.update(stu); // 无效// 提交事务,关闭 Session

Hibernate缓存机制

什么是缓存?

  缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。  

缓存有什么好处?

  缓存的好处是降低了数据库的访问次数,提高应用性能,减少了读写数据的时间

什么时候适合用缓存?

  程序中经常用到一些不变的数据内容,从数据库查出来以后不会去经常修改它而又经常要用到的就可以考虑做一个缓存,以后读取就从缓存来读取,而不必每次都去查询数据库。因为硬盘的速度比内存的速度慢的多。从而提高了程序的性能,缓存的出现就会为了解决这个问题

Hibernate中的缓存

  Hibernate中的缓存包括一级缓存(Session缓存)二级缓存(SessionFactory缓存)查询缓存

    

    一级缓存(Session缓存)

    由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。Session级缓存是必需的,不允许而且事实上也无法卸除。在Session级缓存中,持久化类的每个实例都具有唯一的OID。

    当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load(),以及调用查询接口的list()、iterate()或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。

    当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。

    Session为应用程序提供了两个管理缓存的方法:evict(Object obj):从缓存中清除参数指定的持久化对象。clear():清空缓存中所有持久化对象。

    public static void testOneLeveCache(){Session session=HibernateUtil.getSession();//获取持久化对象DeptDept d1=(Dept)session.get(Dept.class, 10);//再次获取持久化对象DeptDept d2=(Dept)session.get(Dept.class, 10);    session.close();}

   通过Session的get()方法获取到了Dept对象默认会将Dept对象保存到一级缓存中(Session缓存) 当第二次获取的时候会先从一级缓存中查询对应的对象(前提是不能清空或关闭Session否则一级缓存会清空或销毁)如果一级缓存中存在相应的对象就不会到数据库中查询  所以只执行一次查询的查询代码如下:

Hibernate: selectdept0_.DEPTNO as DEPTNO0_0_,dept0_.DNAME as DNAME0_0_,dept0_.LOC as LOC0_0_ fromSCOTT.DEPT dept0_ wheredept0_.DEPTNO=?

  如何清除一级缓存?

  通过session.clear();//清除所有缓存

    session.evict();//清除指定缓存

    public static void testOneLeveCache(){Session session=HibernateUtil.getSession();SessionFactory sf = HibernateUtil.getSessionFactory();//获取持久化对象DeptDept d1=(Dept)session.get(Dept.class, 10);session.clear();//清除所有缓存session.evict(d1);//清除指定缓存//再次获取持久化对象DeptDept d2=(Dept)session.get(Dept.class, 10);    session.close();}

使用session.evict(Object obj)会删除指定的Bean所以当你查询被你删除二级缓存的Bean时也会执行两条SQL语句

使用Session.clear()清除后会发现执行了两条SQL语句:

Hibernate: selectdept0_.DEPTNO as DEPTNO0_0_,dept0_.DNAME as DNAME0_0_,dept0_.LOC as LOC0_0_ fromSCOTT.DEPT dept0_ wheredept0_.DEPTNO=?
Hibernate: selectdept0_.DEPTNO as DEPTNO0_0_,dept0_.DNAME as DNAME0_0_,dept0_.LOC as LOC0_0_ fromSCOTT.DEPT dept0_ wheredept0_.DEPTNO=?

  

    二级缓存(SessionFactory缓存)

  由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。

  save、update、saveOrupdate、load、get、list、query、Criteria方法都会填充二级缓存

  get、load、iterate会从二级缓存中取数据session.save(user)

  如果user主键使用“native”生成,则不放入二级缓存.

  第二级缓存是可选的,是一个可配置的插件,默认下SessionFactory不会启用这个插件。Hibernate提供了org.hibernate.cache.CacheProvider接口,它充当缓存插件与Hibernate之间的适配器。

Hibernate的二级缓存策略的一般过程如下:
    
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
    2) 把获得的所有数据对象根据ID放入到第二级缓存中。
    3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
    4) 删除、更新、增加数据的时候,同时更新缓存。
  Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的查询缓存(Query Cache)。

配置二级缓存(SessionFactory缓存)

  在hibernate.cfg.xml中配置以下代码

    <!-- 开启二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property><!-- 为hibernate指定二级缓存的实现类 --><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

  指明哪些类需要放入二级缓存,需要长期使用到的对象才有必要放入二级缓存放入二级缓存的方式有两种:

    1.在hibernate.cfg.xml中配置

<class-cache class="entity.PetInfo" usage="read-only" /> //不允许更新缓存中的对象
<class-cache class="entity.PetInfo" usage="read-write" />  //允许更新缓存中的对象

    2.在Bean.hbm文件中配置

<hibernate-mapping><class name="com.bdqn.entity.Dept" table="DEPT" schema="SCOTT"  ><cache usage="read-only"/>//将这个类放入二级缓存<id name="deptno" type="java.lang.Integer"><column name="DEPTNO" precision="2" scale="0" /><generator class="assigned"></generator></id><property name="dname" type="java.lang.String"><column name="DNAME" length="14" /></property></class>
</hibernate-mapping>

  

  在ehcache.xml配置文件中可以设置缓存的最大数量、是否永久有效、时间等

<defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/>

如何清除二级缓存?

  需要用SessionFactory来管理二级缓存代码如下:

sessionFactory.evict(Entity.class);//清除所有Entity

sessionFactory.evict(Entity.class,id);//清除指定Entity
比如:
//用SessionFacotry管理二级缓存

SessionFactory factory=HibernateUtils.getSessionFactory();//evict()把id为1的Student对象从二级缓存中清除.

factory.evict(Student.class, 1);
//evict()清除所有二级缓存.

factory.evict(Student.class); 

什么样的数据适合存放到第二级缓存中?   
  1) 很少被修改的数据   
  2) 不是很重要的数据,允许出现偶尔并发的数据   
  3) 不会被并发访问的数据   
  4) 常量数据   
不适合存放到第二级缓存的数据?   
  1) 经常被修改的数据   
  2) 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发   
  3) 与其他应用共享的数据。

  查询缓存(Query Cache)

  hibernate的查询缓存是主要是针对普通属性结果集的缓存, 而对于实体对象的结果集只缓存id。

   在一级缓存,二级缓存和查询缓存都打开的情况下作查询操作时这样的:

    查询普通属性,会先到查询缓存中取,如果没有,则查询数据库;查询实体,会先到查询缓存中取id,如果有,则根据id到缓存(一级/二级)中取实体,如果缓存中取不到实体,再查询数据库。

  在hibernate.cfg.xml配置文件中,开启查询缓存    

<!-- 是否开启查询缓存,true开启查询缓存,false关闭查询缓存 -->
<property name="cache.use_query_cache">true</property>

    开启查询缓存后还需要在程序中进行启用查询缓存

public static void testQueryCache(){Session session=HibernateUtil.getSession();String hql="from Emp as e";Query query=session.createQuery(hql);query.setCacheable(true);//启用查询缓存(二级缓存)List<Emp> empList=query.list();session.close();
}        

查询缓存是基于二级缓存机制如果根据Bean的属性查询可以不开启二级缓存代码如下:

      session = HibernateUtils.getSession(); t = session.beginTransaction(); Query query = session.createQuery("select s.name from Student s"); //启用查询缓存    query.setCacheable(true); List<String> names = query.list(); for (Iterator<String> it = names.iterator(); it.hasNext();) { String name = it.next(); System.out.println(name); } System.out.println("================================"); query = session.createQuery("select s.name from Student s"); //启用查询缓存 query.setCacheable(true); //没有发出查询语句,因为这里使用的查询缓存 names = query.list(); for (Iterator<String> it = names.iterator(); it.hasNext();) { String name = it.next(); System.out.println(name); } t.commit(); 

Hibernate中的三种数据持久状态和缓存机制相关推荐

  1. Hibernate三种数据持久状态:临时态、游离态、持久化状态

    Hibernate中的三种状态   瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID(对象标识符).一般通 ...

  2. (POST请求中的三种数据请求格式.application/x-www-form-urlencoded和multipart/form-data和application/json)

    (POST请求中的三种数据请求格式.application/x-www-form-urlencoded和multipart/form-data和application/json) applicatio ...

  3. 对象在Hibernate中的三种状态

    Hibernate中的对象有3种状态:Transient(瞬时),Persistent(持久)和Detached(托管). 1 瞬时状态: 由new命令开辟内存空间的java对象,例如Student  ...

  4. 图解Hibernate中的三种状态(瞬时态,持久态,游离态|托管态)

    注:  1.  瞬时态转化为持久态时,调用save()方法主要是给瞬时态对象赋值id并把该对象保存到session缓存中 2.  持久态转换为游离态主要是把在session缓存中的对象从session ...

  5. 菜鸟学SSH(八)——Hibernate对象的三种状态

    前面写了几篇关于SSH的博客,但不是Struts就是Spring,Hibernate还从来没写过呢.说好是SSH的,怎么可以光写那两个,而不写Hibernate呢对吧.今天就先说说Hibernate对 ...

  6. Hibernate 对象的三种状态

    Hibernate 对象的三种状态 瞬时(transient): 由new操作符创建,且尚未与Hibernate Session关联的对象被认定为瞬时(Transient)的.瞬时(Transient ...

  7. 【Hibernate框架开发之五】Hibernate对象的三种状态Session常用方法

    1. Hibernate对象的三种状态:(图解如下:) 如图所示,Hibernate对象有三种状态,1.Transient  2.Persistent 3.Detached; 三种状态的区别如下: 1 ...

  8. 061 hive中的三种join与数据倾斜

    一:hive中的三种join 1.map join 应用场景:小表join大表 一:设置mapjoin的方式: )如果有一张表是小表,小表将自动执行map join. 默认是true. <pro ...

  9. 【Arduino串口数据保存到excel中常用三种方法】

    [Arduino串口数据保存到excel中常用三种方法] 1. 前言 2. 利用excel自带Data Streamer读取 2.1 启用 Data Streamer 加载项 2.2 刷写代码并将微控 ...

最新文章

  1. ATS线上报告个别日志过大无法写入问题的解决方法
  2. 1分钟构建API网关日志解决方案
  3. Error: INFO ipc.Client: Retrying connect to server: Already tried XXX time(s).
  4. 算法:最接近的三数之和
  5. OpenCV使用Tensorflow2-Keras模型
  6. Innodb存储引擎——非聚集索引
  7. 小程序 setData 中的坑,其实好像...
  8. Struts 1 和 Struts 2 的线程安全
  9. oracle如何不让表自动建分区,怎么自动创建表空间和表分区
  10. HBase优化案例分析:Facebook Messages系统问题与解决方案
  11. Python安装geopandas库
  12. centos7安装python3.6独立的virtualenv环境
  13. 关于事业发展,雷林鹏教你如何找到方向?
  14. 扩展的几个应用 发布网络YUM源 vim编辑技巧 源码编译安装 systemctl控制
  15. JAVA定时任务Cron表达式解析
  16. R数据分析:列线图的做法及解释
  17. 关于医学影像中的轴位面(横断面)、冠状面、矢状面的解释(转载)
  18. python手机端抢票大麦网_手把手教你用python抢票回家过年 !
  19. it is forbidden to set both [discovery.seed_hosts] and [discovery.zen.ping.unicast.hosts]
  20. java中的常用名词,Java编程基础常见英语词汇

热门文章

  1. 计算机怎样旋转桌面,win7电脑怎么设置翻转屏幕
  2. 启动项 mysql命令大全_mysql常用命令
  3. GOF设计模式之桥接模式
  4. 【Excel】统计不重复数据的个数,设置单元格不允许出现重复数据
  5. 利用js实现 禁用浏览器后退
  6. 贪心 BestCoder Round #39 1001 Delete
  7. MyEclipse的Debug模式
  8. 关于解决Permission is only granted to system apps
  9. ASP.NET MVC3 学习心得------路由机制
  10. POJ 2253 Frogger (求某两点之间所有路径中最大边的最小值)