@GeneratedValue
该注解用于声明主键的生成策略,有两个参数:
1.strategy:
2.generator:
主键生成器的名称,如strategy使用sequence,则该值与@SequenceGenerator注解的name参数保持一致。
不同数据库对strategy的四种取值支持情况不同,如Oracle不支持identity方式,一般使用sequence,mysql一般使用identity。下面测试达梦支持的该参数取值。
Person.java关键代码
@Entity
@Table(name = "Person")
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "IdSeq")
@SequenceGenerator(name="IdSeq", sequenceName="seqPersonId", allocationSize = 1, initialValue = 1)
protected long id;
@Column(name = "name")
protected String name;
该配置会自动在数据库端生成序列和表。
没有提前在数据库创建序列时,根据sequenceName生成序列,自动生成序列的命名规则为:
SQL> SELECT ID FROM SYSOBJECTS WHERE TYPE$ = 'SCH' AND NAME = 'SYSDBA';
行号 ID
---------- -----------
1 150994945
已用时间: 1.708(毫秒). 执行号:127600.
SQL> SELECT NAME, CRTDATE, INFO3 initialValue, INFO4 allocationSize FROM SYSOBJECTS WHERE TYPE$='SCHOBJ' AND SUBTYPE$ = 'SEQ' AND SCHID = '150994945';
行号 NAME CRTDATE initialValue allocationSize
---------- ---------- -------------------------- -------------------- --------------------
1 seqpersond 2023-04-13 11:37:32.845000 1 1
SQL> SELECT NAME, CRTDATE, INFO3 initialValue, INFO4 allocationSize FROM SYSOBJECTS WHERE TYPE$='SCHOBJ' AND SUBTYPE$ = 'SEQ' AND SCHID = '150994945';
行号 NAME CRTDATE initialValue allocationSize
---------- ------------- -------------------------- -------------------- --------------------
1 seq_person_id 2023-04-13 12:32:31.781000 1
注意:
sequenceName="seqPersonId"时,数据库已存在名称为seqPersonId的序列时不报错,会创建seq_person_id序列。库中存在seq_person_id序列时不再创建,使用已存在的序列。
设置自增序列后,插入时带自增列的情况
save接口
@RequestMapping("/save")
@ResponseBody
public String save(){
Person person = new Person();
person.setId(101);
person.setName("张三");
personService.save(person);
return "插入成功";
}
hibernate 日志
Hibernate: select person0_.id as id1_0_0_, person0_.name as name2_0_0_ from person person0_ where person0_.id=?
Hibernate: select seq_person_id.nextval
Hibernate: insert into person (name, id) values (?, ?)
不报错,但手动设置的person.setId(101)不会生效,id值为序列自动生成。
SQL> select *from person;
行号 id name
---------- -------------------- ----
1 1 张三
2 2 张三
已用时间: 0.722(毫秒). 执行号:127603.
Person.java关键代码
@Entity
@Table(name = "Person")
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY,generator = "IdSeq")
// @SequenceGenerator(name="IdSeq", sequenceName="seqPersonId", allocationSize = 1, initialValue = 1)
protected long id;
@Column(name = "name")
protected String name;
使用DmDialect-for-hibernate5.0驱动时启动会报错如下:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: org.hibernate.dialect.identity.IdentityColumnSupportImpl does not support identity key generation
需要使用DmDialect-for-hibernate5.3驱动。
自动生成的表结构
CREATE TABLE "SYSDBA"."person"
(
"id" BIGINT IDENTITY(1, 1) NOT NULL,
"name" VARCHAR(255),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;
测试插入时指定自增列
save接口
@RequestMapping("/save")
@ResponseBody
public String save(){
Person person = new Person();
person.setId(101);
person.setName("张三");
personService.save(person);
return "插入成功";
}
表数据,即strategy=identity时,插入时指定自增列不会报错,也不会生效,自增列实际值还是自增生成。
SQL> select *from person;
行号 id name
---------- -------------------- ----
1 1 张三
已用时间: 0.993(毫秒). 执行号:127604.
从日志可以看到hibernate操作时直接省略了id列的插入。
Hibernate: select person0_.id as id1_0_0_, person0_.name as name2_0_0_ from person person0_ where person0_.id=?
Hibernate: insert into person (name) values (?)
@Entity
@Table(name = "Person")
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO,generator = "IdSeq")
// @GeneratedValue(strategy = GenerationType.IDENTITY,generator = "IdSeq")
// @SequenceGenerator(name="IdSeq", sequenceName="seqPersonId", allocationSize = 1, initialValue = 1)
protected long id;
@Column(name = "name")
protected String name;
自动生成的表结构
CREATE TABLE "SYSDBA"."person"
(
"id" BIGINT NOT NULL,
"name" VARCHAR(255),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;
hibernate日志。此时自动生成一个名为generator参数值的序列,即id_seq,其初始值与步长均为1.
Hibernate: create table person (id bigint not null, name varchar(255), primary key (id))
Hibernate: create sequence id_seq increment by 1 start with 1
插入测试
插入或不插入自增列时,都使用序列值
Person person = new Person();
// person.setId(101);
person.setName("张三");
personService.save(person);
return "插入成功";
}
Hibernate: select id_seq.nextval
Hibernate: insert into person (name, id) values (?, ?)
SQL> select *from person;
行号 id name
---------- -------------------- ----
1 1 张三
已用时间: 0.859(毫秒). 执行号:127608.
但插入带自增列,且自增列唯一时,hibernate在插入前向数据库查询有无该ID值,即便最终自增列值仍使用序列填充。
Hibernate: select person0_.id as id1_0_0_, person0_.name as name2_0_0_ from person person0_ where person0_.id=?
Hibernate: select id_seq.nextval
Hibernate: insert into person (name, id) values (?, ?)
同样,同名序列存在时,使用已存在序列的定义,不再重新创建。
City.java配置
@Entity
@Table(name = "Person")
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "idGenerator01")
// @GeneratedValue(generator = "idGenerator01")
// @GenericGenerator(strategy = "guid", name = "idGenerator01")
// @GeneratedValue(strategy = GenerationType.IDENTITY,generator = "IdSeq")
// @SequenceGenerator(name="IdSeq", sequenceName="seqPersonId", allocationSize = 1, initialValue = 1)
protected long id;
@Column(name = "name")
protected String name;
hibernate日志。这种方式会为每张存在自增列的表创建一张辅助表,当前创建id_generator02表存放自增列信息
Hibernate: create table city (id varchar(255) not null, name varchar(255), primary key (id))
Hibernate: create table id_generator01 (sequence_name varchar(255) not null, next_val bigint, primary key (sequence_name))
Hibernate: insert into id_generator01(sequence_name, next_val) values ('person',0)
Hibernate: create table id_generator02 (sequence_name varchar(255) not null, next_val bigint, primary key (sequence_name))
Hibernate: insert into id_generator02(sequence_name, next_val) values ('city',0)
Hibernate: create table person (id bigint not null, name varchar(255), primary key (id))
查看id_generator01表结构和数据,next_val列为bigint,则使用此种方式时,自增列数据类型必须为数值型。
CREATE TABLE "SYSDBA"."id_generator01"
(
"sequence_name" VARCHAR(255) NOT NULL,
"next_val" BIGINT,
NOT CLUSTER PRIMARY KEY("sequence_name")) STORAGE(ON "MAIN", CLUSTERBTR) ;
表数据
SQL> select *from id_generator01;
行号 sequence_name next_val
---------- ------------- --------------------
1 person 50
已用时间: 2.046(毫秒). 执行号:127613.
此种方式在插入时带自增列会忽略列值,使用辅助表生成的值。
Person.java
@Entity
@Table(name = "Person")
public class Person implements Serializable {
@Id
// @GeneratedValue(strategy = GenerationType.IDENTITY,generator = "IdSeq")
// @SequenceGenerator(name="IdSeq", sequenceName="seqPersonId", allocationSize = 1, initialValue = 1)
protected long id;
@Column(name = "name")
protected String name;
表结构
CREATE TABLE "SYSDBA"."person"
(
"id" BIGINT NOT NULL,
"name" VARCHAR(255),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;
插入测试
save方法
@RequestMapping("/save")
@ResponseBody
public String save(){
Person person = new Person();
// person.setId(101);
person.setName("张三");
personService.save(person);
return "插入成功";
}
插入时不设置自增列,不报错,自动插入值为0,第二次插入时,提示id重复报错。
SQL> select *from person;
行号 id name
---------- -------------------- ----
1 0 张三
已用时间: 0.886(毫秒). 执行号:127605.
插入时带自增列则插入附带的参数值
@RequestMapping("/save")
@ResponseBody
public String save(){
Person person = new Person();
person.setId(101);
person.setName("张三");
personService.save(person);
return "插入成功";
}
SQL> select *from person;
行号 id name
---------- -------------------- ----
1 101 张三
已用时间: 0.781(毫秒). 执行号:127607.
hibernate的中内置了一些生成ID的类,如下:
public DefaultIdentifierGeneratorFactory(boolean ignoreBeanContainer) {
this.generatorStrategyToClassNameMap = new ConcurrentHashMap();
this.ignoreBeanContainer = ignoreBeanContainer;
this.register("uuid2", UUIDGenerator.class);
this.register("guid", GUIDGenerator.class);
this.register("uuid", UUIDHexGenerator.class);
this.register("uuid.hex", UUIDHexGenerator.class);
this.register("assigned", Assigned.class);
this.register("identity", IdentityGenerator.class);
this.register("select", SelectGenerator.class);
this.register("sequence", SequenceStyleGenerator.class);
this.register("seqhilo", SequenceHiLoGenerator.class);
this.register("increment", IncrementGenerator.class);
this.register("foreign", ForeignGenerator.class);
this.register("sequence-identity", SequenceIdentityGenerator.class);
this.register("enhanced-sequence", SequenceStyleGenerator.class);
this.register("enhanced-table", TableGenerator.class);
}
使用guid生成id
@Id
@GeneratedValue(generator = "idGenerator02")
@GenericGenerator(strategy = "guid", name = "idGenerator02")
protected String id;
生成的表结构
CREATE TABLE "SYSDBA"."city"
(
"id" VARCHAR(255) NOT NULL,
"name" VARCHAR(255),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;
hibernate日志
Hibernate: select GUID()
2023-04-13 15:02:48.212 WARN 18748 --- [nio-8080-exec-1] org.hibernate.id.GUIDGenerator : HHH000113: GUID identifier generated: 936E6753DAB44D5345A4B9BA1A98D89F
Hibernate: insert into city (name, id) values (?, ?)
表数据
SQL> select *from city;
行号 id name
---------- -------------------------------- ----
1 936E6753DAB44D5345A4B9BA1A98D89F 张三
已用时间: 1.790(毫秒). 执行号:127609.
插入时指定ID列值,还是使用hibernate生成的guid
Hibernate: select city0_.id as id1_0_0_, city0_.name as name2_0_0_ from city city0_ where city0_.id=?
Hibernate: select GUID()
2023-04-13 15:12:05.735 WARN 24268 --- [nio-8080-exec-1] org.hibernate.id.GUIDGenerator : HHH000113: GUID identifier generated: 4995BFC6259246FFF2EDDDB6D4A778A4
Hibernate: insert into city (name, id) values (?, ?)
@RequestMapping("/citySave")
@ResponseBody
public String save(){
City city = new City();
city.setId("101eab");
city.setName("张三");
cityService.save(city);
return "插入成功";
}
SQL> select *from city;
行号 id name
---------- -------------------------------- ----
1 4995BFC6259246FFF2EDDDB6D4A778A4 张三
已用时间: 0.535(毫秒). 执行号:127610.
使用其他内置类时同理, 修改strategy=类名即可。
@GeneratedValue注解的strategy参数四个取值达梦均支持,具体如下:
自动生成自增列值 | 创建序列(已存在是否重建) | 自增列插入(报错) | 创建辅助表 | 其他 | |
strategy=sequence | 是 | 是(不重建) | 不生效(不报错) | 否 | |
strategy=identity | 是 | 否 | 不生效(不报错) | 否 | |
strategy=auto | 是 | 是(不重建) | 不生效(不报错) | 否 | |
strategy=table | 是 | 否 | 不生效(不报错) | 是 | 需要ID列为数值型 |
不添加注解 | 是(自增列插入为0) | 否 | 生效(不报错) | 否 | |
使用内置类 | 是 | 否 | 不生效(不报错) | 否 | 部分内置类需要ID列为字符型 |
1.使用生成序列的取值类型时,如果库中已存在同名序列则不再替换,使用已存在的序列定义。
2.strategy=identity需要使用DmDialect-for-hibernate5.3。
3.strategy=table时ID列必须为数值型。
文章
阅读量
获赞