JPA Hibernate 主键生成策略
JPA自己提供了四种的主键生成策略:
- AUTO:主键由程序控制。
- IDENTITY:主键由数据库自动生成(主要是自动增长型)
- SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
- TABLE:使用一个特定的数据库表格来保存主键。
1. AUTO
默认的配置。如果不指定主键生成策略,默认为AUTO。
@Id
@GeneratedValue
//或者
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
2. IDENTITY
主键则由数据库自动维护,使用起来很简单。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
3. SEQUENCE
Hibernate同时也对JPA进行了扩展,可以在 GeneratedValue 中指定 generator , 然后用 GenericGenerator 指定策略来维护主键。
@Id @GeneratedValue(generator = "myGenerator") @GenericGenerator(name = "myGenerator", strategy = "uuid")
其中 strategy 有15个选项,分别是
1 public DefaultIdentifierGeneratorFactory() { 2 register("uuid2", UUIDGenerator.class); 3 register("guid", GUIDGenerator.class); 4 register("uuid", UUIDHexGenerator.class); 5 register("uuid.hex", UUIDHexGenerator.class); 6 register("hilo", TableHiLoGenerator.class); 7 register("assigned", Assigned.class); 8 register("identity", IdentityGenerator.class); 9 register("select", SelectGenerator.class); 10 register("sequence", SequenceGenerator.class); 11 register("seqhilo", SequenceHiLoGenerator.class); 12 register("increment", IncrementGenerator.class); 13 register("foreign", ForeignGenerator.class); 14 register("sequence-identity", SequenceIdentityGenerator.class); 15 register("enhanced-sequence", SequenceStyleGenerator.class); 16 register("enhanced-table", TableGenerator.class); 17 }
- uuid2
IdentifierGenerator 的实现类是 UUIDGenerator,具体由 UUIDGenerationStrategy 策略负责生成,它有两个实现 StandardRandomStrategy 和 CustomVersionOneStrategy,他们都是使用j ava.util.UUID 的 api 生成主键的。
StandardRandomStrategy 最终由 UUID.randomUUID(); 生成;
CustomVersionOneStrategy 则采用版本号与位运算通过构造函数 new UUID(mostSignificantBits,leastSignificantBits); 生成。
特点是:不需要和数据库交互,可根据RFC4122定义的5中变量控制具体的生成策略(因为符合RFC4122定义,所以避免了警告信息)
- guid
IdentifierGenerator 的实现类是 GUIDGenerator,通过 session.getFactory().getDialect().getSelectGUIDString(); 获得各个数据库中的标示字符串.
MySQL 用 select uuid();
Oracle 用 return "select rawtohex(sys_guid()) from dual";
特点是:需要和数据库进行一次查询才能生成。数据库全局唯一。
- uuid,uuid.hex
uuid和uuid.hex 两个一个东西。IdentifierGenerator的实现类是UUIDHexGenerator,通过StringBuffer(36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep).append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep).append(format(getCount()))生成。
特点:不需要和数据库交互,全网唯一。
- hilo
IdentifierGenerator 的实现类 TableHiLoGenerator,逻辑较为复杂,通过高低位酸腐生成,但是需要给定表和列作为高值的源。加上本地的地位计算所得。
特点:需要和数据库交互,全数据库唯一,与guid不同的是,在标识符的单个源必须被多个插入访问时可以避免拥堵。
- assigned
IdentifierGenerator 的实现类 Assigned,没有生成逻辑,如果为空就抛出异常。
特点:不需要和数据库交互,自己管理主键生成,显示的指定id。
- identity
IdentityGenerator 并没有直接实现 IdentifierGenerator,而是扩展了AbstractPostInsertGenerator,并实现PostInsertIdentifierGenerator。
而 PostInsertIdentifierGenerator 实现了 IdentifierGenerator,通过IdentifierGeneratorHelper类生成。
这个比较特殊,它返回是个常量 "POST_INSERT_INDICATOR",指在数据库插入后时生成,然后返回数据库生成的id;
还有个常量 "SHORT_CIRCUIT_INDICATOR",是用外键ForeignGenerator时使用的。
特点:需要和数据库交互,数据插入后返回(反查)id,同一列唯一。
- select
SelectGenerator 扩展了 AbstractPostInsertGenerator 实现了 Configurable 接口,而 AbstractPostInsertGenerator 实现了 PostInsertIdentifierGenerator。所以具有和identity类似的行为,有数据库触发器生成。
特点:需要和数据库交互。
- sequence
SequenceGenerator 实现了 PersistentIdentifierGenerator 接口,和 Configurable 接口。
PersistentIdentifierGenerator 接口扩展 IdentifierGenerator 接口,通过不同的数据库,获取不同的取值语句 dialect.getSequenceNextValString(sequenceName); 然后进行查询,缓存到IntegralDataTypeHolder中,通过 generateHolder( session ).makeValue(); 获得。
特点:需要和数据库交互(但不是每次都是)。sequence唯一。
- seqhilo
seqhilo,扩展了 SequenceGenerator, 处理逻辑和 hilo 相同,值不过是使用一个具名的数据库序列来生成高值部分。
特点:需要和数据库交互,全数据库唯一,与guid不同的是,在标识符的单个源必须被多个插入访问时可以避免拥堵。
- increment
IdentifierGenerator 的实现类 IncrementGenerator,并实现了 Configurable 接口。数据库启动时查询表的最大主键列支,并通过 IntegralDataTypeHolder 缓存。插入一条,它自加一。
特点:仅需要首次访问数据库。
- foreign
IdentifierGenerator 的实现类 ForeignGenerator,通过给定的 entityName 和 propertyName 查询获得值。
特点:需要和数据库访问。