【问题标题】:Hibernate: getting too many rows休眠:获取太多行
【发布时间】:2012-09-29 13:00:05
【问题描述】:

我在使用 Hibernate 从数据库中获取行时遇到问题。当我只想得到一行时,我收到了 20 行。当我想从大约 1.5k 行的表中获取所有行时,我正好收到 15.2k 行。 该表的实体类具有复合主键。

这是我获取所有行的代码:

Criteria criteria = getSession().createCriteria(type);
criteria.setCacheable(true).setCacheRegion(BaseEntity.PACKAGE);
criteria.list();

这是我的实体类:

@javax.persistence.Entity
@Table(name = "my_table")
public class My extends MyEntity<MyPK> {

    @EmbeddedId
    private MyPK id;

    @Column(name = "text", nullable = false)
    protected String text;

    @ManyToOne
    @JoinColumn(name = "property", nullable = false, insertable = false, updatable = false)
    protected Option option;

    @Override
    public MyPK getId() {
        return id;
    }

    @Override
    public void setId(MyPK id) {
        this.id = id;
    }

    //getters and setter
}

这是MyPK类:

@Embeddable
public class MyPK implements Serializable {

   @Column(name = "qwerty")
   protected String qwerty;

   @Column(name = "property")
   protected String property;

   //constructors, getters and setters
}

MyEntity 类是带有@MappedSuperclass 注释的抽象类。这是这个类头:

@MappedSuperclass
public abstract class MyEntity<T extends Serializable>

我做错了什么? EmbeddedId 有这个问题吗?

编辑 #1 正如我已经意识到这是问题所在:

@ManyToOne
@JoinColumn(name = "property", nullable = false, insertable = false, updatable = false)
protected Option option;

此对象包含另一个表的外键。而这个另一个表引用了另一个。最后一张表有 10 行用于上一张表。结果我得到行数量 * 10。问题可能出在我的实体中的 Hibernate 注释。

【问题讨论】:

  • 返回的对象都是同一个实例吗?意思是你得到了 20 个完全相同的对象引用吗?
  • @SteveEbersole:我想是的。我明天会检查,因为目前我不能。我从 Hibernate 控制台检查了 sql,我意识到 Hibernate 正在从数据库中获取其他几个表。这些表当然是通过外键连接的。但我不知道为什么简单地从一个表中获取所有行,我的代码得到的附加表很少。对于数据库中的一行,我得到十行作为查询结果。
  • @SteveEbersole :我已经检查过了。我为一个对象获取 10 个实例,为另一个对象获取 10 个实例。

标签: java hibernate persistence criteria


【解决方案1】:

看起来您可能正急切地在某个地方加入多对一关系。默认行为是为数据库返回的每一行获取一个实体。如果您不想更改急切获取,但确实想删除结果中的重复项,则需要使用此ResultTransformer

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

【讨论】:

    【解决方案2】:

    @Embeddable 仅表示 MyPK 的列将是 My 类中的列。 您的问题可能是 @ManyToOne @JoinColumn(name = "property"),因为它与 MyPK 中的 "property" 相同

    【讨论】:

    • 是的,和MyPK中的“property”是一样的。我这样写是因为这是主键的一部分,也是这个表中的外键。
    【解决方案3】:

    您可以使用此方法在条件上设置最大结果数:setMaxResults(int maxResults)

    【讨论】:

    • 是的,我可以,但我需要更复杂的解决方案。
    • 既然有一个简单的解决方案,为什么还要一个复杂的解决方案?!
    • 因为我不知道我想要返回多少行。此计数存储在数据库中,可能会有所不同。
    【解决方案4】:

    主键类需要根据聚合值(qwertyproperty,此处)定义 equals() 和 hashCode()。很可能在处理 ResultSet 时,Hibernate 不会看到跨多行的实体键是相等的。

    来自 JPA 2.0 规范的第 2.4 节(如果有帮助的话):

    主键类必须定义equals和hashCode方法。价值的语义 这些方法的相等性必须与数据库类型的数据库相等性一致 键映射到的位置

    【讨论】:

    • 我已经定义了equals()hashCode(),但我的问题还是一样。您还有其他建议吗?
    • 我想知道我的实体是否正确,所以我也问了这个问题:stackoverflow.com/q/12849545/845220 你能也读一下这个吗?
    猜你喜欢
    • 2016-04-20
    • 2011-08-24
    • 2017-08-06
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 2015-03-04
    • 1970-01-01
    相关资源
    最近更新 更多