首页 > 代码库 > MySQL主键自动生成和生成器表以及JPA主键映射
MySQL主键自动生成和生成器表以及JPA主键映射
MySQL主键自动生成
表设计
MySQL有许多主键生成策略,其中很常见的一种是自动生成。一般情况下,主键类型是BIGINT UNSIGNED,自动生成主键的关键词是AUTO_INCREMENT。
CREATE TABLE Stock ( id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, NO VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, price DECIMAL(6,2) NOT NULL, UNIQUE KEY Stock_NO (NO), INDEX Stock_Name(name) ) ENGINE = InnoDB;
JPA主键映射
@Entity @Table(name = "Stock", uniqueConstraints = { @UniqueConstraint(name = "Stock_NO", columnNames = { "NO" }) }, indexes = { @Index(name = "Stock_Name", columnList = "name") }) public class Stock { private long id; private String no; private String name; private double price; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public long getId() { return id; } public void setId(long id) { this.id = id; }@GeneratedValue(strategy = GenerationType.IDENTITY):实体主键生成策略是自动生成,兼容MySQL主键自动生成策略,关键词是AUTO_INCREMENT。若是MySQL主键没有指定AUTO_INCREMENT,报出以下异常。
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
uniqueConstraints = {
@UniqueConstraint(name = "Stock_NO", columnNames = { "NO" })
},
indexes = {
@Index(name = "Stock_Name", columnList = "name")
}:创建唯一性索引,索引名字是Stock_NO,针对列是NO,创建索引,索引名字是Stock_Name,针对列是name。只有启动了模式生成,索引生成的配置才能生效。启用模式生成,在配置文件persistence.xml做如下配置:
@UniqueConstraint(name = "Stock_NO", columnNames = { "NO" })
},
indexes = {
@Index(name = "Stock_Name", columnList = "name")
}:创建唯一性索引,索引名字是Stock_NO,针对列是NO,创建索引,索引名字是Stock_Name,针对列是name。只有启动了模式生成,索引生成的配置才能生效。启用模式生成,在配置文件persistence.xml做如下配置:
<properties> <property name="javax.persistence.schema-generation.database.action" value=http://www.mamicode.com/"drop-and-create" />>模式生成虽然很方便,能自动生成表结构,但是,由它生成的表结构不总是最佳的,而且还不能保证是正确的。因此,作为最佳实践,不建议在生产环境启用模式生成,手工维护表机构。禁用模式生成,在配置文件persistence.xml做如下配置:
<properties> <property name="javax.persistence.schema-generation.database.action" value=http://www.mamicode.com/"none" />>生成器表
主键的生成策略是生成器表,这种策略不常见,一般用于遗留数据库使用JPA。否则的话,主键的生成策略一般会选择自动生成(GenerationType.IDENTITY)或是序列生成(GenerationType.SEQUENCE)。往目标表插入一条数据之间,JPA实现者从生成器表选择一条关于目标表的主键记录,该记录保存目标表的主键。JPA实现者增大该主键值,然后把该主键增大之前的那个值插入目标表。MySQL生成器表
CREATE TABLE CreatorKey ( TableName VARCHAR(64) NOT NULL PRIMARY KEY, KeyValue BIGINT UNSIGNED NOT NULL, INDEX CreatorKey_Table_Values (TableName, KeyValue) ) ENGINE = InnoDB;MySQL目标表
CREATE TABLE Student ( id BIGINT UNSIGNED NOT NULL PRIMARY KEY, name VARCHAR(100) NOT NULL, INDEX Student_name (name) ) ENGINE = InnoDB;JPA主键映射
@Entity @Table public class Student { private long id; private String name; @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "studentGenerator") @TableGenerator(name = "studentGenerator", table = "creatorkey", pkColumnName = "TableName", pkColumnValue = http://www.mamicode.com/"Publishers",>name :主键生成策略定义的名字;table:生成器表在数据库中的名字;pkColumnName:生成器表的主键列的名字;pkColumnValue:生成器表主键列的值;valueColumnName:生成器表值列的名字;initialValue:生成器表初始值;allocationSize:生成器表数值递增或递减幅度。generator:主键生成策略定义的名字,该属性与name属性保持一致;generator = "studentGenerator":使用生成器表的主键生成策略。主键@TableGenerator的属性initialValue,allocationSize
根据源代码,注解@TableGenerator的属性initialValue、allocationSize是可选的,并且默认值分别是0、50。/** * (Optional) The initial value to be used to initialize the column * that stores the last value generated. */ int initialValue() default 0; /** * (Optional) The amount to increment by when allocating id * numbers from the generator. */ int allocationSize() default 50;但是,根据实际测试结果,情况并非如源代码表示的那样。清空生成器表creatorkey、目标表student,去掉属性initialValue、allocationSize,执行持久化操作。Student student = new Student(); student.setName("张三"); manager.persist(student);得到的结果却是这样的。从上图可以看出生成器表初始值并非为0,递增或递减幅度并非为50。而且每次重启web server后,初始值和递增幅度都是不确定的。更重要的是,主键的生成已经和生成器表失去了联系,KeyValue一致停留在某个值,不会变化。因此,建议在写注解@TableGenerator时,虽然属性 initialValue、 allocationSize是可选的,但要明确为这两个属性指定数值。令人惊讶的是,即使是明确为这两个属性指定数值,很多时候,也会出现上述的问题。经测试,把initialValue、 allocationSize都设置为1时,运行正常。主键@TableGenerator的范围
根据源代码,在同一个持久化单元内,@TableGenerator的主键生成策略定义是全局的,可以被其他实体引用。/** * Defines a primary key generator that may be * referenced by name when a generator element is specified for * the {@link GeneratedValue} annotation. A table generator * may be specified on the entity class or on the primary key * field or property. The scope of the generator name is global * to the persistence unit (across all generator types).
但是,根据实际测试结果,情况并非如源代码表示的那样。即使在同一持久化单元内,@TableGenerator的主键生成策略定义只对定义它的实体生效。@Entity @Table public class Book implements Serializable { private long id; @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "studentGenerator") public long getId() { return this.id; } public void setId(long id) { this.id = id; }启动web server,报出如下异常。javax.persistence.PersistenceException: [PersistenceUnit: EntityMappings] Unable to build Hibernate SessionFactory Caused by: org.hibernate.AnnotationException: Unknown Id.generator: studentGenerator org.hibernate.AnnotationException: Unknown Id.generator: studentGenerator若在实体Book加上对主键生成策略的定义,就运行正常。@Entity @Table public class Book implements Serializable { private long id; @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "studentGenerator") @TableGenerator(name = "studentGenerator", table = "creatorkey", pkColumnName = "TableName", pkColumnValue = http://www.mamicode.com/"Publishers",>
MySQL主键自动生成和生成器表以及JPA主键映射
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。