码迷,mamicode.com
首页 > Web开发 > 详细

3.1 hibernate持久化类及一级缓存

时间:2018-08-16 01:03:03      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:加载   sed   编码   也会   play   保存   int   讲解   hid   

1.持久化类编写规则

Hibernate是持久化层的ORM映射框架,专注于数据的持久化工作。

持久化:所谓的持久化就是讲内存中的数据永久保存到关系型数据库中。

持久化类:其实所谓的持久化类指的是一个Java类与数据库表建立了映射关系,那么这个类称为是持久化类。其实,你可以简单的理解为就是一个Java类,该类通过一个映射文件与数据库的表建立了关系。持久化类的编写规则如下:

  1.持久化类提供无参数构造:因为在hibernate的底层需要使用反射生成类的实例;
  2.成员变量私有,提供共有get/set方法访问.需提供属性;因为Hibernate底层会将查询到的数据进行封装;
  3.持久化类中的属性,应尽量使用包装类型:因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更清晰,而基本数据类型不容易描述。举个例子:假设表中有一列员工工资,如果使用double类型,如果这个员工工资忘记录入到系统中,系统会将默认值0存入到数据库,如果这个员工工资被扣完了,也会在系统中存入0。那么这个0就有了多重含义,而如果使用包装类型就会避免以上情况,如果使用Double类型,忘记录入工资就会存入null,而这个员工工资被扣完了,就会存入0,不会产生歧义。
  4.持久化类需要提供oid.与数据库中的主键列对应;因为hibernate中需要用过这个唯一的标识oid区分在内存中是否是同一个持久化类实例。在java中通过地址区分是否是同一个对象的,在关系型数据库的表中是通过主键区分是否同一条记录。那么hibernate就是通过这个oid来进行区分的。hibernate是不允许在内存中出现两个oid相同的持久化对象的。
  5.不要用final修饰class:因为Hibernate中有延迟加载的机制,这个机制中会产生代理对象,hibernate产生代理对象使用的是字节码的增强技术完成的,其实就是产生了当前类的一个子类对象实现的。如果使用了final修饰持久化类,那么就不能产生子类,从而就不会产生代理对象,那么Hibernate的延迟加载策略(是一种优化手段)就会失效。(hibernate使用cglib代理生成代理对象.代理对象是继承被代理对象.如果被final修饰.将无法生成代理.)

持久化类我们已经可以正常编写了,但是在持久化类中需要有一个唯一标识OID与表的主键去建立映射关系。而且主键一般我们是不会让客户手动录入的,一般我们是由程序生成主键。那么Hibernate中也提供了相应的主键生成的方式,那么我们来看下hibernate的主键生成策略。

 

2. Hibernate主键生成策略

主键的类型:在讲解Hibernate的主键生成策略之前,先来了解两个概念,即自然主键和代理主键,具体如下:

  • 自然主键:表的业务列中,有某个业务列符合:必须有,并且不重复的特征时,该列可以作为主键使用,称之为自然主键;例如在customer表中,如果把name字段作为主键,其前提条件是:每一个客户的姓名不允许为null,并且不允许客户重名,并且不允许修改客户姓名。尽管这是可行的,但是不能满足不断变化的业务需求,一旦出现了允许客户重名的业务需求,就必须修改数据模型,重新定义表的主键,这给数据库的维护增加了难度。
  • 代理主键:表的业务列中,没有某业务列符合:必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键;把不具备业务含义的字段作为主键,称之为代理主键。该字段一般取名为ID,通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间。在上面的例子中,显然更合理的方式是使用代理主键。

Hibernate提供了几个内置的主键生成策略,其常用主键生成策略的名称和描述如下:

  • 自然主键类型
    • assigned:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入;由java程序负责生成标识符,如果不指定id元素的generate属性,则默认使用该主键生成策略。适用于自然主键。
  • 代理主键
    • sequence: Oracle中的主键生成策略.Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列,适用于代理主键。
    • increment(了解): 主键自增.由hibernate来维护.每次插入前会先查询表中id最大值.+1作为新主键值;用于long、short、或int类型,由hibernate自动以递增的方式生成唯一标识符,每次增量为1。只有当没有其它进程向同一张表中插入数据时才可以使用,不能再集群环境下使用。适用于代理主键。
    • identity: 采用底层数据库提供的主键生成标识符,条件是数据库支持自动增长数据类型。在DB2、MySQL、MS SQLServer、Sybase和HypersonicSQL数据库中可以使用该生成器,该生成器要求在数据库中把主键定义成为自增长类型,适用于代理主键。
    • hilo(了解): 高低位算法.主键自增.由hibernate来维护.开发时不使用.
    • native:hilo+sequence+identity 自动三选一策略.根据底层数据库对自动生成标识符的能力来选择identity、sequence、hilo三种生成器中的一种,适合跨数据库平台开发。适用于代理主键。
    • uuid: 产生随机字符串作为主键. 主键类型必须为string 类型. Hibernate采用128位的UUID算法来生成标识符。该算法能够在网络环境中生成唯一的字符串标识符,其UUID被编码为一个长度为32位的十六进制字符串。这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间,适用于代理主键。

 

3. Hibernate持久化对象的三种状态

了解了主键的生成策略之后,我们可以进一步来了解持久化类了。hibernate为了更好地管理持久化类,特将持久化类分成了三种状态,分别是:瞬时态、持久态、托管态,一个持久化类的实例可能处于三种不同状态中的某一种。

  • 瞬时状态

没有id,没有在session缓存中;瞬时态就称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识oid(相当于主键值),尚未与hibernate Session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。

  • 持久化状态

有id,在session缓存中;持久态的对象存在持久化标识oid,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久化对象是在事务还未提交前变成持久态的。

  • 游离|托管状态

有id,没有在session缓存中;托管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了托管态。托管态对象存在持久化标识oid,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,托管状态对象发生改变时,hibernate不能检测到。

 

技术分享图片

我们之前已经介绍了持久化对象的三种状态了,其实我们主要去研究持久太对象就够了,持久态对象其实有一个非常重要的特性:持久化对象可以自动更新数据库。

实例:

1. 编写测试代码

技术分享图片
 1 @Test
 2     public void demo7() {
 3         // 开启事务
 4         Transaction tx = session.beginTransaction();
 5         // 获得持久化对象
 6         Customer customer = session.get(Customer.class, 1l);
 7         customer.setCust_name("nakelulu");
 8         // 不调用session.update(customer);
 9         tx.commit();
10         session.close();
11     }
demo7

技术分享图片

hibernate自动调用update方法。

 

4. hibernate的一级缓存

  • Hibernate缓存原理

缓存是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是内存。

Hibernate的缓存分为一级缓存和二级缓存,hibernate的这两级缓存都位于持久化层,存储的都是数据库数据的备份。其中第一级缓存为Hibernate的内置缓存,不能被卸载。

Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的oid值在Hibernate的一级缓存中进行查找,如果找到匹配oid值得对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同oid值的对象,则会去数据库中查找相应的数据。

当从数据库中查询到所需的数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。 

  在Session接口的实现中包含一系列的Java集合,这些Java集合构成了Session缓存。只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。故一级缓存也被称为是Session基本的缓存。

Hibernate的一级缓存有如下特点:

1. 当应用程序调用Session接口的save()、update()、saveOrUpdate()时,如果Session缓存中没有相应的对象,hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。

2. 当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。

3. 当调用Session的close()方法时,Session缓存会被清空。

技术分享图片

证明一级缓存的存在:

技术分享图片
 1 @Test
 2     public void demo8() {
 3         Transaction tx = session.beginTransaction();
 4         Customer customer1 = session.get(Customer.class, 1l);        // hibernate查询数据库
 5         System.out.println(customer1);
 6         Customer customer2 = session.get(Customer.class, 1l);        // 不查询数据库
 7         System.out.println(customer1==customer2);                    // true
 8         System.out.println(customer2);
 9         tx.commit();
10         session.close();
11     }
demo8

技术分享图片

  • 一级缓存的内部结构(快照区)

Hibernate向一级缓存放入数据时,同时复制一份数据放入到hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用oid判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照:如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

技术分享图片

 

3.1 hibernate持久化类及一级缓存

标签:加载   sed   编码   也会   play   保存   int   讲解   hid   

原文地址:https://www.cnblogs.com/eaglesour/p/9484523.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!