hibernate 主键生成策略
数据库表主键的知识点:
Generator 为每个 POJO 的实例提供唯一标识。
一般情况,我们使用“native”。class 表示采用由生成器接口net.sf.hibernate.id.IdentifierGenerator 实现的某个实例,其中包括:
assigned
主键由外部程序负责生成,在 save() 之前指定一个。
hilo
通过hi/lo 算法实现的主键生成机制,需要额外的数据库表或字段提供高位值来源。
seqhilo
与hilo 类似,通过hi/lo 算法实现的主键生成机制,需要数据库中的 Sequence,适用于支持 Sequence 的数据库,如Oracle。
increment
主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。这种方式可能产生的问题是:不能在集群下使用。
identity
采用数据库提供的主键生成机制。如DB2、SQL Server、MySQL 中的主键生成机制。
sequence
采用数据库提供的 sequence 机制生成主键。如 Oralce 中的Sequence。
native
由 Hibernate 根据使用的数据库自行判断采用 identity、hilo、sequence 其中一种作为主键生成方式。
uuid.hex
由 Hibernate 基于128 位 UUID 算法 生成16 进制数值(编码后以长度32 的字符串表示)作为主键。
uuid.string
与uuid.hex 类似,只是生成的主键未进行编码(长度16),不能应用在 PostgreSQL 数据库中。
Foreign
使用另外一个相关联的对象的标识符作为主键。
以上转自:http://www.cnblogs.com/jams742003/archive/2009/11/20/1606993.html
以下转自:http://blog.csdn.net/yangkaixin1226/article/details/4743158
《浅析Hibernate中uuid和native的主键生成策略在对象存贮的过程区别》
Hibernate 中 uuid 主键生成策略
只有当一个单元测试类在执行 session.save() 才会分配 id ,即将一个对象从 transient 状态转换为 persistent 状态。但是如果这个对象的 id 号是如果 uuid 算法分配的,( uuid 是由 hibernate 生成的,而 native 则是相应的数据库生成的),则数据库中目前还没有存在与之相对应的记录(此时也没有向数据库中发送 sql 语句),此时 hibernate 把这个对象放一个临时集合和一个 PersistenceContext ( Hibernate 用 Map 实现的)中,直到执行 commit ()方法才会将对象放在数据库中,其实在 commit() 执行之前会隐含的执行 flush() 方法, flush() 方法会清理缓存,即把临时集合清空,并由此形成一条 insert语句,到 persistenceContext 中的 entityEntries 中寻找相应的对象信息,并把 existsInDatebase 变为 true 。最后再发送相应的 sql 语句,将对象存储在数据库中。即执行 flush() 方法之后就已经发送 sql 了,最后进行 commit 方法用于提交事务,但是如果利用单元测试的 debug ,在执行完 flush() 方法之后,利用 sql select 语句查找,则还找不到相应的记录,原因是由于数据库的隔离级别,通常数据库中存在四个隔离级别, Read Uncommited , Read Commited , Repeatable Read ,Serialiable Read 。 mysql 使用的是第三个级别, oracle 使用的是第二个级别,级别越高对其并发性要求越严格,在 mysql下可以使用: select @@tx_isolation; 查看相应的级别。 set transaction isolation level read uncommited, 更改其级别为 read uncommited ,这样就能够查看到相应的数据。其实在 flush() 方法之后发送了 sql 就将对象放在数据库中,由于隔离级别的影响直到 mysql 提交之事务之后才可以读。其实事务就是封装一些连续性的操作,可以在未提交时错误发生的时候进行回滚,保证其原子性。
用代码段示例:
User user = new User(); user.setName("Kevin"); user.setPassword("123"); // 因为 user 的主键生成侧路采用的是 uuid ,所以调用完成 save 后,只是将 user 纳入到了 session 的管理 // 不会发出 insert 语句,但是 id 已经生成, session 中 existsInDatebase 状态为 false session.save(user); // 调用 flush , hibernate 会清理缓存,执行 sql // 如果数据库的隔离级别设置为为提交读,那么我们可以看到 flush 过的数据 // 并且 session 中 existsInDatebase 状态为 true session.flush(); // 提交事务 // 默认情况下 commit 操作会先执行 flush 清理缓存,所以不用显示的调用 flush // commit 后数据是无法回滚的 tx.commit();
Hibernate 中 native 主键生成策略
因为 user 的主键生成策略是 native ,调用 session.save() 后将生成 id ,并向数据库中发送 sql 语句,此时在 Read Uncommited 级别下能够读到相应的数据。相当于在 native 策略下 save ()方法之后会自动调用 flush (),清理了缓存,并向数据库发送 sql 。
示例代码段:
User2 user = new User2(); user.setName("Kevin"); // 因为 user 的主键生成策略为 native, 所以调用 session.save 后,将执行 insert 语句,返回有数据库生成的 id // 纳入了 session 的管理,修改了 session 中 existsInDatebase 状态为 true // 如果数据库的隔离级别设置为为提交读,那么我们可以看到 save 过的数据 session.save(user); tx.commit();