1、主键生成策略
OID:对象里面没有主键的概念,对象中对应主键的属性,称为OID(对象标识符);OID用来唯一标明一个对象实体(加上对象类型),OID在对象里面不见得只有一个属性;(映射复合主键),同时OID是一种特殊的属性,所以属性上的column,type,access都可以在元素使用;
OID分为自然主键和代理主键; 代理主键:没有任何业务逻辑的主键;(推荐使用) 自然主键:有业务逻辑的主键;
一般情况下,会使用OID来重写equals和hashCode方法;
1.1、assigned
assigned只能针对一个自然主键来说;(手动设置主键值,都用assigned)
1.2、uuid
(1)主键的类型必须是string;
(2)主键的值是hibernate生成的,所以hibernate在插入对象之前,已经知道对象的主键值了;
(3)可以使用uuid
1.3、increment;
(1)主键类型需要是long ,integer等可以增加的数字类型;
(2)首先查询出当前表最大的id,id+1再设置为当前对象的主键值;
(3)hibernate会把每一个类型的increment值缓存起来,提高性能;
(4)hibernate在插入对象之前,已经知道对象的主键值了
(5)increment性能较高,不能在集群的环境下使用;
1.4、identity
使用数据库本身的自增主键生成方式;
(1)对于MYSQL来说,其实我们使用native的时候,就是使用了identity方式;
(2)要使用identity,必须要求数据库支持自增的方式,SQL SERVER(identity)
(3)oracle不支持identity方式;
(4)不支持数据库的迁移;
1.5、native
native就是使用数据库支持的主键生成方式;
对于MYSQL来说,使用identity;
对于ORACLE来说,使用sequence;
1.6、TableGenerator
使用一个额外的表(默认hibernate_sequences)来模拟序列生成器;
(1)如果没有其他配置,hibernate会使用一个叫做default的序列生成器为所有的对象生成主键;
(2)可以设置segment_value来为每一个对象单独创建一个序列生成器;
(3)默认情况下,每生成一个主键需要两个SQL,性能不高(1,select:获取当前id;2,update:更新next_val)
(4)性能提升,increment_size:设置一次可以取多少个值;(但是会造成id的不连续,cache)
(5)数据库无关的,(在迁移的时候要拷贝hibernate_sequences表);
(6)所以hibernate在插入对象之前,已经知道对象的主键值了;
(7)table是一种非常好的主键生成方式;
<id name="id">
<generator class="org.hibernate.id.enhanced.TableGenerator">
<param name="segment_value">IDDOMAIN_SEQ</param>
<param name="initial_value">1</param>//初始值
<param name="increment_size">100</param>//每次存入初始值之间的差值
</generator>
</id>
存入对象的时候回生成一张中间表
执行后发出的SQL;
Hibernate: select tbl.next_val from hibernate_sequences tbl where tbl.sequence_name=? for update
Hibernate: update hibernate_sequences set next_val=? where next_val=? and sequence_name=?
Hibernate: insert into IdDomain (name, id) values (?, ?)
Hibernate: insert into IdDomain (name, id) values (?, ?)
1.7、选择
(1)判断使用自然主键还是代理主键;(自然主键assigned)
(2)是否需要有数据库迁移的需求;(使用数据库无关的生成策略;)
(3)性能
(4)是否在集群环境使用;
(5),单应用使用navtive;
2、session的方法补充
2.1、load方法
(1)get方法,在调用get方法的时候就会立刻去发送一条SELECT查询,如果没有结果,返回null,如果有结果,返回对象,
(2)load方法和get一样,也能够查询指定id的对象;
(3)load方法把真正执行select延后到了使用这个对象的时候,我们叫做延迟加载;
(4)什么叫使用这个对象?在使用对象非主键属性的时候;
(5)load方法的原理:
a、load方法返回的对象是hibernate动态为我们的domain创建的一个子类;
b、hibernate在这个子类里面重写了非主键的属性的getter方法,和tostring方法;
c、hibernate为这个子类添加了一个(是否加载完成)的状态;如果在调用这个对象的getter方法的时候,这个对象还没有被加载,就发送SQL去查询对象,并且把查询到的结果设置到对象中,并设置是否加载完成状态为[加载完成];如果之后再去调用getter方法,因为已经加载完成了所以,只需要直接返回这些属性的值就可以了;
d、hibernate使用javassist来完成延迟加载子类的动态生成;
e、如果在session关闭之前没有去实例化延迟加载对象
f、用load方法返回的对象永远不可能为空;
g、如果load方法返回的对象在使用的过程中发现数据库里面没有值对应,报错;
h、如果要使用load方法,请保证id在数据库中一定存在;
2.2、其他方法
(1)saveOrUpdate:保存没有id的对象,修改有id的对象;
(2)persist:
- 把对象保存到数据库中;
- persist方法要执行,必须在事务空间之内;
(3)merge:
- 相当于update方法;
- merge方法要执行,必须在事务空间之内;
3、hibernate对象状态
首先看一下我们在使用hibernate中几个匪夷所思的问题:
- 主键的生成策略不同,发送INSERT语句的时间不一样?
- 删除对象的时候其实并没有立刻发送delete语句?
- 为什么get方法得到的对象,修改了属性,会发送UPDATE语句?
3.1、临时状态
**刚new出来,没有id,[数据库里面没有值对应],**一下几种情况产生临时状态对象:
- new 语句刚创建了一个对象。
- 删除状态的对象session提交,对象处于临时状态。
- use_identifier_rollback
3.2、持久化状态:
有id,并且被session(hibernate)管理,[数据库里面有值对应]
- save方法把临时对象变成持久化状态,save方法把游离对象变成另一个持久化对象。
- get方法返回的对象是持久化状态
- load方法返回的对象是持久化状态
- Query.list()方法返回的实体对象是持久化状态,在处理大数据量的时候,需要及时清理缓存。
- update方法把游离对象变成了持久化对象。
3.3、游离状态
有id,没有被session(hibernate)管理,[数据里面有值对应]
- session.close()方法把所有(关闭的那个session)持久化对象变成游离对象
- session.clear()方法把所有(调用clear方法的session)持久化对象变成游离对象
- session.evict(Object)方法把指定的持久化对象变成游离对象。
3.4、删除状态
有id,计划被删除,[数据库里面有值对应]
- delete方法让持久化状态和游离状态变成删除状态。但是删除状态的对象必须要等到session刷新,事务提交之后才真正的从数据表里面删除。
对象不同状态间的相互转换如下图所示:
结合对象状态间的相互转换,我们来回答刚刚提到的几个问题。
(1)主键的生成策略不同,发送INSERT语句的时间不一样?
因为save方法是把对象从临时–>持久化,它只需要去找到ID即可;不同的主键生成策略,有的必须要发送insert才能够得到id(assigned,identity、native),有的不需要发送insert就能够得到id(uuid、increment、TableGenerator),所以这时候,就不需要发送insert语句了;
(2)删除对象的时候其实并没有立刻发送delete语句?
因为delete方法仅仅只是把游离对象或持久化对象变成删除对象,所以他并非不负责sql的发送;
(3)为什么get方法得到的对象,修改了属性,会发送UPDATE语句?
这个问题应该修改为持久化对象的属性真正发生变化的时候,才会去发送UPDATE语句;
总结:由session的持久化方法改变对象的状态,在同步session时候(默认情况是提交事务/flush),session再同步脏数据到数据库,完成内存对象和数据库内容的同步;
一句话:session负责改变状态 提交事务负责同步数据
到底在提交事务的时候,要发送哪些SQL?
(1)会把由临时对象变成的持久化对象的SQL发送;—>insert;
(2)会把持久化状态和游离状态变成的删除状态发送SQL—>delete;
(3)会把游离状态变成持久化状态的对象发送SQL;
(4)会把脏的持久化状态对象自动同步到数据库中;
(5)通过session.flush方法,可以手动同步数据库;