我如何结合 TABLE_PER_CLASS 和 GenerationType.IDENTITY

How can I combine TABLE_PER_CLASS and GenerationType.IDENTITY

亲爱的未来reader:在完成和他提供的link之后,我决定改用序列。较新的 Hibernates 注意它也适用于 MySQL。


我有一个 abstract class,其中包含我希望在我的所有实体中拥有的一些基本值(例如 ID、创建日期、创建用户等)。目前,我正在为每个具体 class 具有 table 并使其 id 工作的组合而苦苦挣扎。

看来我可以有一个 table 每个 class 或一个我配置 ID 的地方,但不能同时有两个。这对我来说似乎很奇怪而且不太可能,所以我想确保情况确实如此。

可能相关的版本:hibernate 5、mysql 5.5、java 1.8、spring 4.3。

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@MappedSuperclass
public abstract class GeneralData implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false)
    protected int id;
    protected String name;

    // getters, setters, constructors, etc.
}

示例子class:

@Entity
public class ExampleClass extends GeneralData {
    // own values, constructors, getters, setters, etc.
}

我得到的错误:

Cannot use identity column key generation with <union-subclass> mapping for: org.example.ExampleClass

我尝试过的事情:

我不想将 id 列移动到每个具体 class。如果 ID 仅对单个 table 而不是整个依赖树唯一,我完全没问题。

如果我应该升级我的库、数据库等,请记住,这只能通过大量额外的工作来完成(出于内部原因)。这将是最后的手段,我希望首先看到一些它有帮助的证据。

对同一父实体的所有子对象的要求是它们之间具有唯一的 ID。

例如,假设您有一个父实体 GeneralData,然后使用 id=1 存储子类型 A。 这将是完全合法的:

GeneralData loaded = entitymanager.find( GeneralData.class, 1 );

当然 loaded 的类型将是 A:子类。 映射必须确保没有歧义:不允许其他子类也使用“1”作为 ID,即使它映射到不同的 table

在你的例子中,你要求 Hibernate 将 GeneralData 的每个不同子类型存储到它自己单独的 Table.

您还要求 MySQL - 它不知道这些 table 以任何方式相关 - 自动分配唯一标识符。

无法指示 MySQL 这些 table 中的每一个都需要使用相同的 Identity "sequence",因为它们不是真正的序列:因此此映射是非法的!这会给您带来麻烦,因为它会将重叠 ID 分配给父实体的不同子类型,这违反了上述语义。

这是使用 IDENTITY 的局限性的一个很好的例子;此外,IDENTITY 不是很有效,因为它意味着 Hibernate 需要在实体持久化后立即写入实体,而不是能够更有效地将刷新操作推迟到更合适的时间,因此可能会批量写入或完全跳过它们(特别是如果事务被中止,而且如果您在持久化之后更新实体但仍在同一事务中)。

我建议看看不同的 Identifier generator strategies for such hierarchies, and in particular Optimizers 可能会大大提高您的应用程序的性能。

每个具体 class 映射可以有 2 个不同的 table :

  • 对于隐式多态性,无法使用多态查询,但您可以使用 IDENTITY 策略(正如 Sanne 指出的那样效率不高)。标识符可以在 superclass 或 subclasses.
  • 中定义
  • with union, 不允许 IDENTITY 策略(Sanne 已经清楚地解释了原因)。标识符必须在 superclass
  • 中定义

第一个映射是

@MappedSuperclass
public abstract class GeneralData implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false)
    protected int id;
    protected String name;

    ....
}

@Entity
public class ExampleClass extends GeneralData {
    ...
}

而第二个映射是

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class GeneralData implements Serializable {
....
}

@Entity
public class ExampleClass extends GeneralData {
   ...
}