hibernate详解(二)---主键生成策略和对象状态

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方法,可以手动同步数据库;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值