【问题标题】:Why does Hibernate sometimes load instances of an incorrect subclass?为什么 Hibernate 有时会加载不正确子类的实例?
【发布时间】:2015-09-11 18:26:07
【问题描述】:

我们有一个奇怪的休眠问题,我们无法解释。

我们有什么:

  1. 一个抽象类和它的两个子类。我们称它们为 A、SubA1、SubA2
  2. 我们还有另一个抽象类和一些子类。让我们呼叫 B、SubB1、SubB2。
  3. SubB1 和 A 之间存在多对一关系。
  4. 类 A 和 B 的休眠映射如下所示:

    <hibernate-mapping>
    
      <class name="A" table="A" lazy="false">
    
        <id name="id" column="ID" type="java.lang.Integer">
          <generator class="org.hibernate.id.enhanced.TableGenerator">
            <param name="segment_value">a</param>
          </generator>
        </id>
    
        <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />
    
        <joined-subclass name="SubA1" table="SUB_A1" lazy="false">
          <key column="ID_A" foreign-key="FK_SUB_A1_A"/>
          <property name="p1" column="p1" length="255" unique="true"/>
          <property name="p2" column="p2" length="255" not-null="true" />
        </joined-subclass>
    
        <joined-subclass name="SubA2" table="SUB_A2" lazy="false">
          <key column="ID_A" foreign-key="FK_SUB_A2_A"/>
          <property name="p3" column="p3" length="255" not-null="true" unique="true" />
          <property name="p4" column="p4" length="4000" />
        </joined-subclass>
    
      </class>
    
    </hibernate-mapping>
    

<hibernate-mapping>

  <class name="B" table="B" lazy="false">

    <cache usage="read-write"/>

    <id name="id" column="ID" type="java.lang.Integer">
      <generator class="org.hibernate.id.enhanced.TableGenerator">
        <param name="segment_value">b</param>
      </generator>
    </id>

    <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />

    <joined-subclass name="SubB1" table="SUB_B1" lazy="false">
      <key column="ID_B" foreign-key="FK_SUB_B1_B"/>
      <many-to-one name="subA" column="ID_A" not-null="false" update="false" foreign-key="FK_SUB_B1" lazy="false" class="A"/>
    </joined-subclass>

  </class>

</hibernate-mapping>

现在的问题是:有时休眠通过加载 SubB1 的项目将 SubA2 的项目加载为 SubA1 的实例,但并非所有项目都会投错,只有少数项目,而且每次都不是相同的项目。

也许有人可以解释一下,我们的休眠映射出了什么问题或出了什么问题。

提前谢谢你。

附言。 此问题发生在:

  • JDK 1.7.71
  • Oracle 12g
  • 休眠 3.6.10

我没有尝试其他配置。

很遗憾,我没有示例应用程序,但我也无法给出真实应用程序的源代码。

【问题讨论】:

  • 你能指定你的环境(Hibernate、JDK、数据库的版本)吗?拥有完整的示例应用程序也很好。
  • @sibnick 我添加了有关 Hibernate、JDK 和数据库的信息。
  • 你是应用程序多线程,集群吗?您使用什么类型的二级缓存提供程序?你能在没有缓存的情况下重复错误吗?
  • 您在子类上的 Key 列不应该只是 &lt;key column="ID"&gt; 而没有 _A(和 _B)吗?您的 Notation 应该生成名为 ID_A 的列,它与 ID 无关,除了外键约束。这将允许有 2 个条目(在任一表中)引用某个 ID A,这可能是您的问题。您可以添加一些示例数据吗? ID 在所有(子)类中应该是唯一的。
  • @sibnick 是的,我可以在禁用第二个缓存的情况下重现此错误。我们正在使用 EHCache

标签: java oracle hibernate


【解决方案1】:

我认为您的休眠映射是正确的。因此,如果您有错误,我相信它会发生在施法时间。我多次遇到这个问题,我总是使用 Visitor Pattern 解决它。

访问者模式的另一个优点是您不需要强制lazy=false,因为它完美地解决了代理对象的真实类型。

如何解决您的问题

我建议您创建一个 Visitor 类,该类为每个 A 具体子类实现两个 visit 方法:

  • void visit(SubA1 object)
  • void visit(SubA2 object)

这两种方法的实现是当A实例是SubA1SubA2具体类时要执行的代码。我把void return,但显然你可以改变它。

另一方面,A类必须添加抽象访问方法public abstract void visit(Visitor visitor);。再次,我把void返回,但是你必须适应visit方法的返回类型。

SubA1SubA2 必须按如下方式实现此方法:

public void accept(Visitor visitor) {
    visitor.visit(this);
}

这样,当您运行此代码objectA.accept(visitor) 时,Java 必须在运行时解析objectA 的真实类型,而无需强制转换,也不会出现错误。它真的很有效,我在 Hibernate 3.x 和 4.x 中使用了多年。

访问者模式文档

在这里您有一篇非常好的文章Proxy Visitor Pattern,您可以在其中找到如何在使用代理和非代理对象时将访问者模式应用于休眠。

希望对你有帮助!

【讨论】:

  • 您是否尝试过我的反对意见?我正在给你你的问题的答案。这是我多次解决的常见问题。
  • 感谢您的回答。投反对票的不是我。假期回来我会试试你建议的访客模式
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
  • 2020-06-07
相关资源
最近更新 更多