一个人至少拥有一个梦想,有一个理由去坚强

心若没有栖息的地方,到哪里都是在流浪

jdbc4.MySQLSyntaxErrorException: Table 'XX.hibernate_sequence'

 

工作中用的是mybatis,已经很久没接触spring data jpa,最近跟着别人项目实践一番

用的正是spring data jpa,遇到一些小坑,便记录下来。

 

一、没有添加主键策略报错如下:

Caused by: org.hibernate.id.IdentifierGenerationException:
         ids for this class must be manually assigned before calling save(): com.clover.sell.dataobject.ProductCategory
  at org.hibernate.id.Assigned.generate(Assigned.java:33)
  at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:105)

解决上述错误,添加主键策略即可。

如何指定主键策略:注解@Id 和 @GeneratedValue即可指定

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id")
private Integer categoryId;

二、主键策略踩坑

我的数据库语言是mysql:

添加不正确的

@Id
@GeneratedValue
private Integer categoryId;

或者这样:

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Integer categoryId;

报错如下:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'sell.hibernate_sequence' doesn't exist
  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_144]
  at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_144]
  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_144]
  at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_144]
  at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.45.jar:5.1.45]
  at com.mysql.jdbc.Util.getInstance(Util.java:408) ~[mysql-connector-java-5.1.45.jar:5.1.45]

调用JpaRepository 的save() 方法保存数据,便报上面的错误。

网上查找答案,原来是我主键自增策略有问题。

改为如下正常

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer categoryId;

三、主键策略介绍

4种JPA策略用法

我们点进@GeneratedValue源码里可以看到,strategy属性是由GenerationType指定的,

我们点进GenerationType里面可以看到这里定义了四种策略:
– TABLE:使用一个特定的数据库表格来保存主键。
– SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
– IDENTITY:主键由数据库自动生成(主要是自动增长型)
– AUTO:主键由程序控制(也是默认的,在指定主键时,如果不指定主键生成策略,默认为AUTO)
这些策略也不是所有数据库都支持的,支持情况如下表:

策略\数据库 mysql oracle postgreSQL kingbase
TABLE 支持 支持 支持 支持
SEQUENCE 不支持 支持 支持 支持
IDENTITY 支持 不支持 支持 支持
AUTO 支持 支持 支持 支持

mysql的主键策略使用 @GeneratedValue(strategy = GenerationType.IDENTITY)

 

Hibernate拓展id策略

当然,很多时候,这么几种策略并不够用,这里hibernate也拓展了JPA的id策略,我们可以在org.hibernate.id.IdentifierGeneratorFactory中看到,主要提供了这么些策略:
1. native: 对于oracle采用Sequence方式,对于MySQL和SQL Server采用identity(自增主键生成机制),native就是将主键的生成工作交由数据库完成,hibernate不管(很常用)。
2. uuid: 采用128位的uuid算法生成主键,uuid被编码为一个32位16进制数字的字符串。占用空间大(字符串类型)。
3. hilo: 使用hilo生成策略,要在数据库中建立一张额外的表,默认表名为hibernate_unique_key,默认字段为Integer类型,名称是next_hi(比较少用)。
4. assigned: 在插入数据的时候主键由程序处理(很常用),这是generator元素没有指定时的默认生成策略。等同于JPA中的AUTO。
5. identity: 使用SQL Server和MySQL的自增字段,这个方法不能放到Oracle中,Oracle不支持自增字段,要设定sequence(MySQL和SQL Server中很常用)。等同于JPA中的IDENTITY。
6. select: 使用触发器生成主键(主要用于早期的数据库主键生成机制,少用)。
7. sequence: 调用底层数据库的序列来生成主键,要设定序列名,不然hibernate无法找到。
8. seqhilo: 通过hilo算法实现,但是主键历史保存在Sequence中,适用于支持Sequence的数据库,如Oracle(比较少用)。
9. increment: 插入数据的时候hibernate会给主键添加一个自增的主键,但是一个hibernate实例就维护一个计数器,所以在多个实例运行的时候不能使用这个方法。
10. foreign: 使用另外一个相关联的对象的主键。通常和联合起来使用。
11. guid: 采用数据库底层的guid算法机制,对应MYSQL的uuid()函数,SQL Server的newid()函数,ORACLE的rawtohex(sys_guid())函数等。
12. uuid.hex: 看uuid,建议用uuid替换。
13. sequence-identity: sequence策略的扩展,采用立即检索策略来获取sequence值,需要JDBC3.0和JDK4以上(含1.4)版本 。
具体使用就是多了一个@GenericGenerator注解,指定策略,指定自定义名称,然后在@GeneratedValue中使用该策略,比如:

@Id
@GenericGenerator(name = "myUUid", strategy = "uuid")
@GeneratedValue(generator  = "myUUid")
@Column(name = "id")
private String id;

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注