持久化类
javabean+映射文件
编写规范:
(1)提供一个无参数的构造器:
此构造器可以不是被public所修饰,但是只要有无参构造器,Hibernate就可以使用Constructor.newInstance()来创建持久化类实例了,为了方便Hibernate在运行时生成代理,构造器的访问修饰符至少是包可见的。
(2)提供一个标识属性:标识属性通常映射数据库表的主键字段。
(3)为持久化类的每个成员变量提供setter、getter方法;
(4)使用非final类(若使用final修饰,load方法的懒加载失效,就和get一样了);
(5)重写equals()和hashCode()方法:
主键生成策略
主键类型分类
自然主键:使用实体中一个有具体业务意义的字段作为主键 例如:身份证号
★代理主键:使用实体中一个毫无任何具体业务意义的字段作为主键 例如 user_id product_id
hibernate中常用的主键生成策略:
native: 对于 oracle 采用 Sequence 方式,对于MySQL 和 SQL Server 采用identity(自增主键生成机制),native就是将主键的生成工作交由数据库完成,hibernate不管(很常用)。
uuid: 采用128位的uuid算法生成主键,uuid被编码为一个32位16进制数字的字符串。占用空间大(字符串类型)。
assigned: 在插入数据的时候主键由程序处理(很常用),这是 <generator>元素没有指定时的默认生成策略。等同于JPA中的AUTO。
identity: 使用SQL Server 和 MySQL 的自增字段,这个方法不能放到 Oracle 中,Oracle 不支持自增字段,要设定sequence(MySQL 和 SQL Server 中很常用)。 等同于JPA中的INDENTITY。
sequence: 调用底层数据库的序列来生成主键,要设定序列名,不然hibernate无法找到。
foreign: 使用另外一个相关联的对象的主键。通常和<one-to-one>联合起来使用。
uuid.hex: 看uuid,建议用uuid替换。
持久化对象的三种状态
在hibernate中持久化类的对象可以划分为三种状态,分别是瞬态,持久态,脱管态。
- 瞬态(Transient),也叫临时态。处于这种状态的对象具备的特征如下:
a) 不在Session的缓存中,不与任何的Session实例相关联。
b) 在数据库中没有与之相对应的记录。 - 持久态(Persistent),处于这种状态的对象具备的特征如下:
a) 在Session的缓存中,与Session实例相关联。
b) 在数据库中存在与之相对应的记录。 - 脱管态(Detached),也叫游离态。处于这种状态的对象具备的特征如下:
a) 不在Session的缓存中,不与任何的Session实例相关联。
b) 在数据库中存在与之相对应的记录。(前提条件是没有其他Session实例删除该条记录)。
持久化对象的三种状态是可以相互转化的,具体转换过程如图所示:
一级缓存和快照机制
session的一级缓存
使用hibernate进行查询的时候,将查询结果放置到session的一级缓存中,在一级缓存中存在对象,对象使用属性的OID的值进行区分,此时再使用相同的OID进行查询的时候,首先会在session一级缓存中进行查找是否存在相同的OID
如果存在相同的OID,此时不再查询数据库,而是直接使用一级缓存中存在的对象
如果没有存在相同的OID,此时再查询数据库,将查询得到的结果数据再放置到session一级缓存中
目的:减少访问数据库的次数
session的快照
使用id进行查询数据库,将查询得到的结果放置到session一级缓存中,同时复制一份数据,放置到session的快照中
当使用tr.commit()的时候,同时清理session的一级缓存(flush)
如果2个对象(一级缓存对象和快照的对象)中的属性发生变化,则执行update语句,此时更新数据库,更新成一级缓存中的数据
如果2个对象中的属性不发生变化,此时不执行update语句
目的:确保和数据库中的数据一致
hibernate中的事务
同时运行多个事务访问相同数据时,可能会导致5类并发问题:
- 第一类丢失更新:撤销一个事务时,把其他事务已提交的更新覆盖
- 脏读:一个事务读到另一事务未提交的更新数据
- 虚读:一个事务读到另一事务已提交的新插入的数据
- 不可重复读:一个事务读到另一事务已提交的更新数据
- 第二类丢失更新:一个事务覆盖另一事务已提交的更新数据,不可重复读的特例
在hibernate中也有四种隔离级别,分别是
1—Read uncommitted isolation 读未提交数据
2—Read committed isolation 读已提交数据
4—Repeatable read isolation 可重复读
8—Serializable isolation 串行化
如何设置隔离级别? 在核心配置文件中配置:
<property name="hibernate.connenction.isolation">4</..>
如何保证service层和dao层使用的同一个事务?——–只需要保证service层和dao层使用同一个连接即可
如何何保证service层和dao层使用同一个连接?方式1:传递参数 方式2:使用线程绑定的方式(ThreadLocal)
hibernate如何使用事务,底层封装好了ThreadLocal
步骤:
1.在核心配置文件中配置 将session绑定到当前线程中
<!-- 开启与线程绑定的session -->
<property name="hibernate.current_session_context_class">thread</property>
2.factory.getCurrentSession();获取和当前线程绑定的session。(注意:此时的session不需要手动关闭)