三、Hibernate映射对象标识符(OID)

映射对象标识符:

Java语言按内存地址来识别和区分同一个类的不同对象,而关系数据库按主键值来识别和区分同一个表中的不同记录。Hibernate使用对象标识符(OID)来建立内存中的对象和数据库中记录的对应关系,对象的OID和数据库表的主键对应。

主键的分类 业务主键 VS 代理主键 代理主键是不具有业务性的;

一般来说,主键不应该含有业务含义(维护性问题),含有业务含义的主键称为自然主键,尽管可行,但有业务含义的主键不利于系统的维护,如某项业务改变可能会涉及到数据库表的改变,给维护带来了困难。比较合理的方式是使用代理主键(一般为ID),使主键不具备业务含义。

通常情况下,把主键(代理主键)定义为自动增长的标识符类型(代理主键的类型一般为short、int、long),许多数据库提供了自动增长的供,但不尽相同。

Hibernate区分对象是怎么做的呢?

1.我们在数据库准备两条数据:t_student(关于配置及建表,可参考我上篇博客)

2.单元测试方法:

看控制台打印:

为什么查三次只有两次访问数据库呢?

由此我们可以得到,对于相同的主键,Hibernate是从session缓存中取的,并不会再一次访问数据库。Hibernate底层是通过OID来区分对象的。

既然说到了Id 那我们就简单谈一下 Hibernate对象标识符的生成策略:

1,increment 由 Hibernate 自动以递增的方式生成标识符,适用代理主键;

Student.hbm.xml:

TestStudent:

看控制台执行:

 保存一个对象两条sql,可以看出在insert语句时含有ID字段,说明Hibernate在持久化时会议递升的方式生成标识符

为了证明我们的结论 我们看一下数据库生成的表:

主键没有自动递增,所以 当用increment生成策略的时候,是Hibernate去查询然后底层默认加1 进行插入的 而不是利用数据库。

select max(ID) from customers;

这种标识符生成方式一般只在拥有一个服务器的数据库使用,在集群环境下会出现生成的标识符相同的问题。(好像是多线程问题无法执行数据库事务问题)

2,identity 由底层数据库生成标识符;适用代理主键;

Student.hbm.xml:

TestStudent:

我们再执行,看控制台:

只有一条SQL,我们再看下数据库生成的表:

默认自动增长,说明了identity标识符生成器有底层数据库来负责生成标识符,他要求底层数据库把主键定义为自动增长字段类型。

3,sequcence 由 Hibernate 根据底层数据库的序列来生成标识符;适用代理主键;mysql不支持 oracle 和 db2支持

<hibernate-mapping package="com.model">  
  
    <class name="Customer" dynamic-insert="true"dynamic-update="true">  
  
       <id name="id" type="long"column="ID">  
  
           <meta attribute="scope-set">private</meta>  
  
           <generator class="sequence">  
  
              <param name="sequence">customers_id_seq</param>  
  
           </generator>  
  
       </id>  
  
       <property name="name" type="string">  
  
           <column name="NAME" length="15"></column>  
  
       </property>  
  
    </class>  
  
</hibernate-mapping>  

oracle生成的表SQL:

create table customers(  
  
    ID bigint not null,  
  
    NAME varchar(15) not null  
  
    primary key (ID)  
  
);  
create sequencecustomers_id_seq;

生成了sequence序列。
insert into customers(NAME,ID)values(?,?); 

insert SQL中包含有ID字段,可见hibernate先从数据库中的customers_id_seq序列中获得一个唯一的序列号。

Sequence依赖底层数据库的序列,需要数据库支持序列才行,但是Mysql不支持。

4,hilo Hibernate 根据 high/low 算法来生成标识符。适用代理主键 

insert SQL中含有ID字段,hibernate负责生成标识符,hilo生成标识符时读取hi_valu表中的next_value的值,并修改,这是由数据库的事务处理的,不是hibernate事务。

Hilo不依赖与底层数据库,所有具有通用性,,但是只能在一个数据库中保证唯一。,但用户自行提供数据库连接时或者使用JTA时,应用程序无法使用hilo,这种情况下如果数据库支持序列,可以使用seqhilo

5,native 根据底层数据库对自动生成标识符的支持能力, 来选择 identity,sequence 或 hilo;适用代理主键;

insert SQL语句中没有ID字段,由数据库底层生成标识符。

由于是根据各种数据库的自动生成序列,,适合跨平台开发。同一个hibernate连接多种数据库系统。

因为native 选择identity、sequence、hilo标识符生成器,所以效果和identity 一样 就不演示了。

参考文章:ID生成策略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值