Hibernate 的主键生成策略

Hibernate 是一个 ORM 框架,它的核心作用就是建立内存中的 Java 对象和数据库表中的记录的对应关系。

Java 语言按照内存地址来区分不同的对象,而关系数据库中则按照主键值来区分同一个表中的不同记录。那 Hibernate 作为中间人,如何建立记录和对象之间的关系呢?它是通过在 POJO 对象中维护一个 OID(对象标识符) 来统一这两者的矛盾。POJO 对象中的 OID 属性值和数据库中对应记录的主键值是相同的。也就是说任何一个对象纳入 Session 管理时,都必须拥有 OID ,否则 Session 根本无法管理对象。

也就是说 Hibernate 要求 POJO 类必须拥有一个 OID 属性,从某种程度上来说,这也算是 Hibernate 对业务逻辑层的一种侵入,但这也是没有办法的事情。所以通常也只是说 Hibernate 低侵入性!

Hibernate 的主键生成策略常用的有以下几个:

  • native,表示此 POJO 对象的对象标识符OID 由具体使用的数据库生成。POJO 的标识符类型只能是整数类型,比如 short 、int 、long 类型的数据。一般默认用这个作为主键生成策略!要注意它并不是一种具体的主键生成策略,它是根据核心配置文件中的方言来动态决定调用那种生成策略,比如 identitysequence
    • identity,适用于 short 、int 、long 类型的主键,它采用的是数据库提供的主键自动增长机制,所以只能用在支持自增长机制的数据库中,比如 MySQL、MSSqlServer ,Oracle 是不支持主键自增长的。
    • sequence,适用于序列的方式生成主键,比如 Oracle 数据库就支持这种方式,MySql 就不支持。
  • increment,适用于 short 、int 、long 类型的主键,这是 Hibernate 的自动增长机制,原理其实很简单。它发送的是一条这样的 sql 语句select max(id) from xx,找到最大的主键,然后让 id + 1 ,再作为下一条记录的主键。也就是说该策略要求数据库也要支持自增长,比如 Oracle 就是不行的。而且使用该方式存在线程安全问题,如果两个线程同时读取到的是同一个 id ,这就会造成混乱,典型的脏数据问题。
  • uuid表示由 Hibernate 采用 UUID 算法生成 OID。它将当前应用的 IP 地址,JVM 启动时间,系统时间,JVM 中的计数器的值按照一定的规则生成的一个占据 16 个字节长度的字符串。POJO 标识符类型只能是 String 类型,由于太消耗空间,一般不推荐使用。
  • foreign,表示用另一个对象的标识符来作为当前对象的标识符,通常用在对象一对一关联的主键映射当中。
  • assigned,此方式由自己在应用程序中手工指定,不推荐使用。

总结一下,主键生成策略可以分为三类:

  • 由数据库决定生成主键方式,有identitysequence两种,但是为了使用方便,直接用native替代就可以。
  • 由 Hibernate 生成主键的方式,一种是使用increment,另一种是使用uuid方式。
  • 第三种就是由程序指定,使用assigned。或者是取决于其他记录的foreign方式。

native 主键生成策略

xxx.hbm.xml文件中给对象标识符指定生成策略的配置方式如下:


    

由于这种主键生成方式需要具体的数据库来决定,所以 Session 调用save()方法的时候,Hibernate 就会执行 insert 语句将对象的值插入到数据库中,以得到标识符,才能够将该对象纳入到 Session 的缓存中进行管理。

补充:主键分为自然主键和代理主键,所谓自然主键就是有具体业务含义的,比如以学号、身份证号为主键。代理主键就是没有任何实际业务含义的,开发中推荐使用这种方式。

你可能感兴趣的:(Hibernate 的主键生成策略)