映射对象标识符:
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生成策略