Hibernate 生成策略和缓存策略

主键生成策略

1、主键分类

1. 天然主键

主键自己就是表中的一个字段,实体中一个具体的属性,对象自己惟一的特性redis

好比:建立一个学生表:姓名、年龄、身份证号(天然主键)sql

2. 代理主键

主键自己不是表中必须的一个字段数据库

一样建立一个学生表:姓名、年龄 、身份证号、SID(代理主键)缓存

在实际开发当中尽可能要使用代理主键session

  • 设计以学生身份证号为主键
  • 在业务上添加学生身份证号,不当心录入错误
  • 主键修改是若是两个相同是容许修改的。因此一旦参于业务,就可能存在一些问题
  • 主键通常只做为条件,查询,不参与修改,使用代理主键就和表当中的业务信息没有关系

开发中为何要使用代理主键多线程

  • 一旦天然主键参与到业务逻辑当中,后期有可能修改源代码
  • 一个好的程序设计要知足开闭原则(Open Closed Principle)
    • 对程序的扩展是open开放的
    • 对修改源码是close的

2、主键的生成策略

  • 在使用代理主键的过程中,尽可能要作到自动生成主键,不能让用户手动设置主键
  • 通常交给数据库自动增加,让程序生成惟一的标识
  • 在hibernate当中,为了减小程序的编写,内部提供了多种的主键生成策略

1. increment

  • 自动增长策略(long、short、int)
  • 原理
    • 首先先发送一条语句:select max(id) from 表
    • 而后让id加1
  • 在单线程中使用,不要在多线程中使用
    • 两个线程同时对数据库当中的id字段查询
    • 两我的查询的内容都是1
    • 其中一个确定会报错

2. identity

  • 自动增加
  • 原理
    • 使用是数据库底层的增加策略
    • 适用于有自动增加机制的数据库
      • Mysql有自动增加
      • Oracle是没有自动增加的:经过序列来完成这种效果的

3. sequence

  • 自动增加
  • 原理
    • 采用序列的方式
    • 必须得要支持序列
      • Oracle支持序列
      • Mysql不支持序列

4. uuid

  • 适用于字符串类型的主键
  • 使用hibernate中随机生成字符串的主键

5. native

  • 本地策略
  • 在 identity 和 sequence 自动切换

6. assigned

  • hibernate不会帮你管理主键
  • 本身手动调用或经过程序来去生成主键

持久化

1、什么是持久化

  • 将内存中的一个对象持久化到(存储到)数据库的过程
  • hibernate框架就是一个持久化的框架

2、什么是持久化类

  • 一个Java类与数据库创建的映射关系
  • 持久化类 = Java类 + 映射文件

3、持久化类编写规则

1.对持久化类提供一个无参的构造方法

  • 底层会经过反射建立对象
  • 若是没有无参构造,反射是没法建立对象的

2.对内部私有的字段要提供get与set方法

  • 不提供的话。hibernate就没法获取对象的值

3.对象持久化类提供一个OID与数据库表当中的主键对应

  • Java中经过对象的地址来区别是否为同一个对象
  • 数据库中经过主键来区别是不是同一条记录
  • Hibernate中经过持久化类的OID属性来区分是不是同一个对象

4.持久化类中的属性尽可能使用包装类型

  • 包装类型的默认值为NULL
  • 基本数据类型的默认值为数字

5.持久化类不要使用final修饰

  • 跟延时加载有关系
  • 延时加载是Hibernate优化的手段
  • 返回的是一个代理对象
  • 使用动态代理 ,低层使用的是字节码加强技术,继承这个类来进行代理。
  • 若是使用了final,就不能被继承,不能被继承,代理对象就没法建立,延时加载就无效了。

持久化类的划分

  • Hibernate是持久层的框架,经过持久化类完成ORM操做
  • 持久化类:Java类+映射文件

Hibernate为了更好的管理持久化类,将持久化类对象分为三种状态

1. 瞬时态

  • 没有惟一的OID
  • 没有被session管理
  • 这种对象咱们称为瞬时态对象

2.持久态

  • 有惟一的OID
  • 有被session管理
  • 这种对象咱们称为持久态对象

3.游离态/托管态/离线态

  • 有惟一的OID
  • 没有被session管理

三种状态区分

1. 瞬时态

刚new出对象时,尚未设置id,尚未被session所管理。框架

2. 持久态

已经有了id,调用session方法,把对象给session,才被session所管理 。ide

添加到session以后, 对象一直处理持久态。当对象处理持久态时, 能够自动更新数据库。优化

持久态对象特征
  • 自动更新数据,只要成为持久态对象,不用调用update也会自动更新数据
  • 若是值和数据库当中的值同样, 就不会发送update
  • 原理:依赖了hibernate当中的一级缓存

3. 游离态

把session关闭掉时close时,对象处理游离态。ui

代码演示

三种状态之间的转换

一级缓存

1、什么是缓存

  • 缓存是一种优化的方式,分为一级缓存和二级缓存。
  • 将数据存入到内存当中,使用的时候直接从缓存中获取,不用直接到存储源中取数据了。

2、一级缓存

  • session级别的缓存
  • 生命周期与Session一致:一级缓存是由Session中的一系列Java集合构成的
  • 是自带的, 不可卸载

3、二级缓存

  • SessionFactory级别的缓存
  • 须要本身去配置,默认是开启的,在企业当中通常都不用了,如今都 redis。

4、一级缓存特色

当应用程序用Session接口的Save(),update(),saveOrUpdate()时,若是session缓存中没有相应的对象,就会自动的从数据库查询相应的信息,写到缓存当中。

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

当调用session.close方法时,缓存会被清空。

代码:

5、一级缓存内部结构

一级缓存当中有一个区域:快照区

  • 使用id进行查询数据库,将查询获得的结果放置到session一级缓存中,同时复制一份数据,放置到session的快照中
  • 当使用tr.commit()的时候,同时清理session的一级缓存(flush)
  • 当清理session一级缓存的时候,会使用OID判断一级缓存中对象和快照中的对象进行比对
  • 若是2个对象(一级缓存的对象和快照的对象)中的属性发生变化,则执行update语句,此时更新数据库,更新成一级缓存中的数据
  • 若是2个对象中的属性不发生变化,此时不执行update语句

目的:确保和数据库中的数据一致

清空一级缓存

  • clear():清空全部缓存
  • evict(obj):清空一个对象

事务管理

1、事务

  • 逻辑上的一组操做
  • 要么全都成功,要么全都失败

2、事务特性

1. 原子性

事务不能分隔

2. 隔离性

执行一个事务时, 不该受到其它事务的干扰

  • 脏读:一个事务读取某一个事务未提交的数据
  • 不可重复读:一个事务读取取另外一个事务已经提交的update数据,致使在前一个事务屡次查询的结果不同
  • 幻读:一个事务读取到别一个事务已经提交的insert数据,致使在前一个事务屡次查询的结果不同

3. 持久性

事务完成后, 数据就持久到数据库当中

4. 一致性

事务执行先后 ,数据的完整性要保持一致

3、事务的隔离级别

  • Read uncommitted
    • 全部问题都会发生
  • Read committed
    • 解决脏读问题
  • Repeatable read
    • 解决脏读和不可重复读
  • Serializable
    • 解决全部问题,效率较低

4、Hibernate设置事务的隔离级别

  • 在核心配置文件hibernate.cfg.xml当中
  • 经过数字来表明不一样的隔离级别
<property name="hibernate.connection.isolation">4</property>

5、事务业务层链接

在业务层使用事务时,必须得要保证获取事物的链接和dao层操做的链接是同一个,不然就管理了不对应的操做

1. 使用jdbc当中事务业务层处理方法

(1)向下传递

就开始在业务层先建立好一个链接,传给dao层,让dao层使用这个链接执行操做

(2)使用ThreadLocal对象

在service方法当中把建立的链接绑定到对应的threadLocal当中,在dao方法当中,经过当前的线程得到链接对象

2. hibernate当中处理方法

  • Hibernate框架,内部已经绑定好了ThreadLocal
  • 在SessionFactory中,提供了一个方法,getCurrentSession() 方法,获取当前线程中的session
  • 此方法默认不能用,要经过配置完成
  • 在核心配置文件(hibernate.cfg.xml)当中配置
<property name="current_session_context_class">thread</property>
  • 建立一个session绑定到当前线程
  • 经过它来操做时, 不须要 close,执行结束后, 会自动的close()
相关文章
相关标签/搜索