@GeneratedValue通过MySQL的多态抽象超类 [英] @GeneratedValue polymorphic abstract superclass over MySQL
问题描述
在使用Hibernate和MySQL的Spring MVC应用程序中,我有一个抽象超类 BaseEntity
,用于管理模型中所有其他实体的ID值。 id
字段使用 @GeneratedValue
。我遇到一个问题,每当我的代码试图保存任何扩展 BaseEntity
的子类。问题是为 @GeneratedValue
选择 GenerationType
。
In a Spring MVC application using Hibernate and MySQL, I have an abstract superclass BaseEntity
that manages the values of the IDs for all the other entities in the model. The id
field uses @GeneratedValue
. I am encountering a problem whenever my code tries to save any of the subclasses that extend BaseEntity
. The problem comes with the choice of GenerationType
for the @GeneratedValue
.
在我的代码中, BaseEntity
的子类试图保存到基础MySQL数据库的每个地方,以下错误:
At every place in my code where a subclass of BaseEntity
tries to save to the underlying MySQL database, I get the following error:
ERROR SqlExceptionHelper - Table 'docbd.hibernate_sequences' doesn't exist
我已经阅读了很多关于这个在SO和谷歌,但他们处理其他数据库(不是MySQL)或他们不处理抽象超类。我不能使用 GenerationType.IDENTITY
解决问题,因为我使用抽象超类来管理所有实体的 id
字段在模型中。同样,我不能使用 GenerationType.SEQUENCE
,因为MySQL不支持序列。
I have read many postings about this on SO and on google, but they either deal with other databases (not MySQL) or they do not deal with abstract superclasses. I cannot solve the problem by using GenerationType.IDENTITY
because I am using an abstract superclass to manage id
fields for all entities in the model. Similarly, I cannot use GenerationType.SEQUENCE
because MySQL does not support sequences.
?
以下是 BaseEntity.java
的代码:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected Integer id;
public void setId(Integer id) {this.id = id;}
public Integer getId() {return id;}
public boolean isNew() {return (this.id == null);}
}
下面是扩展 BaseEntity
的实体之一的代码示例:
Here is an example of the code for one of the entities that extends BaseEntity
:
@Entity
@Table(name = "ccd")
public class CCD extends BaseEntity{
//other stuff
}
以下是DDL:
CREATE TABLE IF NOT EXISTS ccd(
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
#other stuff
)engine=InnoDB;SHOW WARNINGS;
这是DAO中的JPQL代码:
Here is the JPQL code in the DAO:
@Override
@Transactional
public void saveCCD(CCD ccd) {
if (ccd.getId() == null) {
System.out.println("[[[[[[[[[[[[ about to persist CCD ]]]]]]]]]]]]]]]]]]]]");
this.em.persist(ccd);
this.em.flush();
}
else {
System.out.println("]]]]]]]]]]]]]]]]]] about to merge CCD [[[[[[[[[[[[[[[[[[[[[");
this.em.merge(ccd);
this.em.flush();
}
}
编辑:
在这种情况下,我不能使用 @MappedSuperClass
的原因是我需要 ManyToOne
关系,允许多个子类型可互换使用。以下面的 AccessLog
类为例。它有一个 actor_entity
和一个 target_entity
。可以有许多类型的actor实体和许多类型的目标实体,但它们都继承自 BaseEntity
。这种继承使MySQL中的底层 accesslogs
数据表只有一个 actor_entity_id
字段,只有一个 target_entity_id
字段,而不是每个字段都有几个字段。当我将 @Entity
上面 BaseEntity
更改为 @MappedSuperClass
会抛出一个不同的错误,指示 AccessLog
找不到 BaseEntity
。 BaseEntity
需要 @Entity
注释才能使 AccessLog
多态性属性。
The reason I cannot use @MappedSuperClass
in this situation is that I need to have ManyToOne
relationships that allow for multiple subtypes to be used interchangeably. Look at the AccessLog
class below as an example. It has an actor_entity
and a target_entity
. There can be many types of actor entities and many types of target entities, but they all inherit from BaseEntity
. This inheritance enables the underlying accesslogs
data table in MySQL to just have one actor_entity_id
field and just one target_entity_id
field instead of having to have several fields for each. When I change @Entity
above BaseEntity
to @MappedSuperClass
, a different error gets thrown indicating that AccessLog
cannot find BaseEntity
. BaseEntity
needs @Entity
annotation in order for AccessLog
to have polymorphic properties.
@Entity
@Table(name = "accesslogs")
public class AccessLog extends BaseEntity{
@ManyToOne
@JoinColumn(name = "actorentity_id")
private BaseEntity actor_entity;
@ManyToOne
@JoinColumn(name = "targetentity_id")
private BaseEntity target_entity;
@Column(name="action_code")
private String action;
//getters, setters, & other stuff
}
根据JBNizet的建议,我创建了一个hibernate_sequences表,如下所示:
SECOND
As per JBNizet's suggestion, I created a hibernate_sequences table as follows:
CREATE TABLE IF NOT EXISTS hibernate_sequences(
sequence_next_hi_value int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
)engine=InnoDB;SHOW WARNINGS;
但现在我得到以下错误:
But now I am getting the following error:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'sequence_name' in 'where clause'
这里是hibernate sql引起的错误,接下来的2行的堆栈跟踪:
Here is the hibernate sql causing the error, followed by the next 2 lines of the stack trace:
Hibernate: select sequence_next_hi_value from hibernate_sequences where sequence_name = 'BaseEntity' for update
ERROR MultipleHiLoPerTableGenerator - HHH000351: Could not read or init a hi value
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'sequence_name' in 'where clause'
这个?
推荐答案
因为您使用TABLE标识符生成器,您需要创建该表。如果您没有使用增强型标识符生成器,您可能会使用 MultipleHiLoPerTableGenerator 。
Because you use the TABLE identifier generator you need to have that table created. If you are not using the enhanced identifier generators, chances are you are going to use the MultipleHiLoPerTableGenerator.
MultipleHiLoPerTableGenerator可以为所有表标识符生成器使用一个表。
The MultipleHiLoPerTableGenerator can use one table for all table identifier generators.
我的建议是从您的集成测试中获取表ddl,以防您使用hbmddl构建测试模式。如果您使用flyway或liquibase进行测试,可以添加 maven插件生成ddl模式。
My suggestion is to grab the table ddl from your integration tests, in case you use hbmddl to build the test schema. If you use flyway or liquibase for testing, you can add a maven plugin to generate the ddl schema.
一旦你有了schema,你需要使用create table命令,并把它添加到MySQL数据库。
Once you have the schema, you need to take the exact create table command and make add it to your MySQL database.
这篇关于@GeneratedValue通过MySQL的多态抽象超类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!