JPA 有一个@GeneratedValue注解,有一个strategy attribute,如
@GeneratedValue(strategy = GenerationType.IDENTITY)

常见的可选策略主要有IDENTITYSEQUENCE

GenerationType.IDENTITY

要求底层有一个 integer 或者 bigint 类型的自增列( auto-incremented column)。自增列的赋值必须在插入操作之后发生,因为这个原因,Hibernate 无法进行各种优化(特别是 JDBC 的 batch 处理,一次 flush 操作会产生很多条insert 语句,分别执行)。如果事务回滚,自增列的值就会被丢弃。数据库在这个自增操作上有个高度优化的轻量级锁机制,性能非常棒。

MySQL 支持这种 id 生成策略,

使用 MySQL 应该尽量使用这个策略,即使它无法优化。

JPA 用它生成 id,会一条一条地插入新的 entity。

GenerationType.SEQUENCE

数据库有一个所谓的 sequence 对象,可以通过 select (而不是 insert )来获取下一个数

它也可以指定一个特殊的 SequenceGenerator,而不是只使用数据库自带的。

MySQL 不支持这种 id 生成方式,Oracle 支持。

*JPA 用它生成 id,会一条一条地 select 出新的 value,然后再 batch insert 新的 entity

jdbc 生成的隐藏 sql

在使用MySQL时,若表中含自增字段(auto_increment类型),则向表中insert一条记录后,可以调用last_insert_id()(对应的操作就是在事务的 insert 里偷偷插入这样一个语句SELECT LAST_INSERT_ID())来获得最近insert的那行记录的自增字段值(一个bigint类型的64-bit值)。

jdbc/mybatis 就是用这样一个语句来获取最新的 id 并绑定在最新的 orm 对象上的。

参考文献:

  1. 《How to generate primary keys with JPA and Hibernate》
  2. 《How do Identity, Sequence, and Table (sequence-like) generators work in JPA and Hibernate》
  3. 【MySQL笔记】last_insert_id()函数使用的注意事项