三大框架 之 Hibernate生成策略与缓存策略(主键生成策略、持久化、持久化类划分、一级缓存、事物管理)

Hibernate生成策略与缓存策略

主键生成策略

主键分类

  • 自然主键

    主键本身就是表中的一个字段

    实体中一个具体的属性,对象本身唯一的特性

    创建一个学生表
    	姓名
    	年龄
    	身份证号(主键)
    
  • 代理主键

    主键本身不是表中必须的一个字段
      创建一个学生表
      		姓名
      		年龄
      		身份证号
      		SID
    这样的主键代理主键
    在实际开发当中尽量要使用代理主键
    		设计以学生身份证号为主键
    		在业务上添加学生身份证号,不小心录入错误
    		主键修改是如果两个相同是允许修改的。所以一旦参于业务,就可能存在一些问题
    		主键一般只作为条件,查询,不参与修改,使用代理主键就和表当中的业务信息没有关系
    
  • 开发中为什么要使用代理主键

    一旦自然主键参与到业务逻辑当中,后期有可能修改源代码
    一个好的程序设计要满足开闭原则(Open Closed Principle)
    	对程序的扩展是open开放的
    	对修改源码是close的
    		oracle
    		mysql
    		jdbc
    		只改配置文件就行
    

主键的生成策略

  • 在使用代理主键的过程当中,尽量要做到自动生成主键,不能让用户手动设置主键
  • 一般交给数据库自动增长,让程序生成唯一的标识
  • 在hibernate当中,为了减少程序的编写,内部提供了多种的主键生成策略
increment
	自动增加策略
		long
		short
		int
	原理
		在单线程中使用,不要在多线程中使用
			两个线程同时对数据库当中的id字段查询
			两个人查询的内容都是1
			其中一个肯定会报错
		先先发送一条语句
			select max(id) from 表
		然后让id加1
identity
	自动增长
	原理
		使用是数据库底层的增长策略
		适用于有自动增长机制的数据库
			Mysql有自动增长
			Oracle是没有自动增长的,是通过序列来完成这种效果的
sequence
	自动增长
	原理
		采用序列的方式
		必须得要支持序列
			Oracle支持序列
			Mysql不支持序列
uuid
	适用于字符串类型的主键
	使用hibernate中随机生成字符串的主键
native
	本地策略
	在identity和sequence自动切换
assigned
	hibernate不会帮你管理主键
	需要自己手动调用或通过程序来去生成主键

持久化

什么是持久化

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

什么是持久化类

  • 一个Java类与数据库建立的映射关系
  • Java类+映射文件

持久化类编写规则

1.对持久化类提供一个无参的构造方法
	底层会通过反射创建对象
	如果没有无参构造,反射是无法创建对象的
	一般,类自带“看不见”的持久化类
2.对内部私有的字段要提供get与set方法
	不提供的话。hibernate就无法获取对象的值
3.对象持久化类提供一个OID与数据库表当中的主键对应
	Java中通过对象的地址来区别是否为同一个对象
	数据库中通过主键来区别是否是同一条记录
	Hibernate中通过持久化类的OID属性来区分是否是同一个对象
4.持久化类中的属性尽量使用包装类型
	包装类型的默认值为NULL
	基本数据类型的默认值为数字
5.持久化类不要使用final修饰
	跟延时加载有关系
	延时加载是Hibernate优化的手段
	返回的是一个代理对象
		使用动态代理 
		低层使用的是字节码增强技术,继承这个类来进行代理
		如果使用了final,就不能被继承
		不能被继承,代理对象就无法创建,延时加载就无效了

持久化类的划分

  • Hibernate是持久层的框架,通过持久化类完成ORM操作
  • 持久化类:Java类+映射文件
  • Hibernate为了更好的管理持久化类,将持久化类对象分为三种状态
瞬时态
	没有唯一的OID
	没有被session管理
	这种对象我们称为瞬时态对象
持久态
	有唯一的OID
	有被session管理
	这种对象我们称为持久态对象
游离态/托管态/离线态
	有唯一的OID
	没有被session管理

三种状态区分

瞬时态
	刚new出对象时,还没有设置id,还没有被session所管理
持久态
	已经有了id
	调用session方法,把对象给session,才被session所管理 
	添加到session之后, 对象一直处理持久态
	当对象处于持久态时, 可以自动更新数据库
游离态
	把session关闭掉时close时
	对象处理游离态

​ 代码演示

持久态对象特征

  • 自动更新数据,只要成为持久态对象,不用调用update也会自动更新数据
  • 如果值和数据库当中的值一样, 就不会发送update

  • 原理是依赖了hibernate当中的一级缓存

一级缓存

什么是缓存

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

​ 缓存
​ 一级缓存
​ 二级缓存

一级缓存

session级别的缓存
生命周期与Session一致
	一级缓存是由Session中的一系列Java集合构成的
是自带的, 不可卸载
	二级缓存是SessionFactory级别的缓存
	需要自己去配置,默认是开启的,在企业当中一般都不用了,现在都用redis

一级缓存特点

当应用程序用Session接口的Save(),update(),saveOrUpdate()时
如果session缓存中没有相应的对象,就会自动的从数据库查询相应的信息,写到缓存当中
当调用Session接口的load,get()方法,以及Query接口的list iterator方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库;如果缓存中没有要查询的对象,再到数据库当中查询对应的对象,并添加到一级缓存中。
当调用session.close方法时,缓存会被清空

代码

一级缓存内部结构

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

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

清空一级缓存

​ clear()
​ 清空所有缓存
​ evict(obj)
​ 清空一个对象

事务管理

什么是事务

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

事务特性

原子性
	事务不能分隔
隔离性
	执行一个事务时, 不应受到其它事务的干扰
		脏读
			一个事务读取某一个事务未提交的数据
		不可重复读
			一个事务读取取另一个事务已经提交的update数据,导致在前一个事务多次查询的结果不一样
		幻读
			一个事务读取到别一个事务已经提交的insert数据,导致在前一个事务多次查询的结果不一样
持久性
	事务完成后, 数据就持久到数据库当中
一致性
	事务执行前后 ,数据的完整性要保持一致

事务的隔离级别

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

Hibernate设置事务的隔离级别

​ 在核心配置文件hibernate.cfg.xml当中
​ 通过数字来代表不同的隔离级别

<property name="hibernate.connection.isolation">4</property>

事务业务层连接

为什么要在业务层使用事务

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

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

	向下传递
		就开始在业务层先创建好一个连接,传给dao层,让dao层使用这个连接执行操作
	使用ThreadLocal对象
		在service方法当中把创建的连接绑定到对应的threadLocal当中
		在dao方法当中,通过当前的线程获得连接对象

hibernate当中处理方法

Hibernate框架,内部已经绑定好了ThreadLocal
在SessionFactory中,提供了一个方法,getCurrentSession()方法
获取当前线程中的session
此方法默认不能用
通过配置完成
	在核心配置文件当中配置
	<property name="current_session_context_class">thread</property>
	创建一个session绑定到当前线程
通过它来操作时, 不需要 close,执行结束后, 会自动的close()
原文地址:https://www.cnblogs.com/mumuyinxin/p/10708263.html