【问题标题】:efficiently loading collection of collections from database in hibernate在hibernate中有效地从数据库加载集合集合
【发布时间】:2017-03-28 09:26:07
【问题描述】:

我有一个带有 hibernate 的 Web 应用程序,它可以管理多种语言的数据。目前基本上每个请求都会生成大量关于语言翻译的选择语句。模型大致如下:

Data <1-1> Placeholder <1-many> languageTranslation <many-1> language

如果我查询所有/许多数据对象,我会看到许多单选,它们为占位符选择一种语言翻译。我最想生成的 SQL:

SELECT * FROM data join placeholder join languagetranslation 
WHERE data.placeholder_id = placeholder.id 
AND languagetranslation.placeholder_id = placeholder.id 
AND languagetranslation.language_id = ?

这样我就可以在一次调用中获取每个带有占位符的数据和翻译。语言翻译有一个复合主键 language_id 和 placeholder_id。

我没有 HBM 文件,一切都通过注释进行管理。型号代码(仅显示相关部分):

@Entity
public class Data {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, optional = false)
    @Fetch(FetchMode.JOIN)
    private Placeholder content;
}

public class Placeholder { 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "primaryKey.placeholder", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
    @Fetch(FetchMode.JOIN)
    private Set<LanguageTranslation> languageTranslations = new HashSet<>();
}

public class LanguageTranslation {

    @EmbeddedId
    private LanguageTranslationPK primaryKey = new LanguageTranslationPK();

    @Type(type = "org.hibernate.type.StringClobType")
    private String text;

}

@Embeddable
public class LanguageTranslationPK {

    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.JOIN)
    private TextPlaceholder textPlaceholder;

    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.JOIN)
    private Language language;
}

public class Language {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}

我尝试了 FetchType 和 FetchMode,但无法生成我想要的行为,它总是单选单语言翻译。

我还尝试了多种查询方式,包括基于条件的、HQL 和原始 SQL。我当前的原始 SQL 查询如下:

String sql_query = "select data.*, lt.* from Data as data join languagetranslation as lt on data.content_id = lt.textplaceholder_id";
Query q = getSession().createSQLQuery(sql_query).addEntity("data", Data.class).addJoin("data.content_id", "data.title").addJoin("lt", "data.content.languageTranslations").setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return q.list();

我在这里做错了吗?如何说服 hibernate 在一个数据库调用中获取所有实体?或者在我的情况下是否有其他方法可以提高性能(例如批量选择)?

【问题讨论】:

  • “在一个数据库调用中获取所有实体”是什么意思?您能否手动模拟您希望收到的查询类型以及您认为应该如何将其转换为对象模型?
  • @Andremoniy 我想要所有带有初始化data.content 和初始化data.content.languageTranslations 的数据对象。所以基本上我想要我展示的 SQL,但休眠知道我已经为它加载了所有占位符和 LanguageTranslations,它不需要再查询它了。

标签: java hibernate


【解决方案1】:

您可以使用 getter setter 和构造函数创建所有实体变量的代理 pojo。然后在休眠查询中初始化这个构造函数,这样你就可以从数据库中获取所有需要的数据。

import com.proxy;
 class userProxy{
private string name;
private string password;
private string address;
private int pincode;
private byte[] profilePic;
private int age;

public userProxy(string name,string password){
  this.name = name;
  this.password = password;
}

//Getter and setter of all variable...
}

然后使用这个构造函数来像 Hibernate 查询一样

select new com.proxy.userProxy(user.name,user.password) from usertable

【讨论】:

  • 但这意味着我必须为每个需要从数据库查询的类编写代理,对吗?我希望我可以避免这种情况。有什么方法可以让 hibernate 为我生成代理或重用原始实体作为代理?
  • 您还有一个选项可以在实体类中创建构造函数,但我还没有尝试过。请尝试一次,如果有效,请告诉我。
  • 是的,我认为这适用于新的构造函数,但对象相同。但看起来必须小心不要触发任何急切的加载等。在这种情况下,像你一样编写代理可能会更少工作,更直接。
  • 我现在按以下方式进行操作: bia this question 我停用休眠干预,然后我可以简单地obj.setProperty(property),该对象将表现为 POJO。这样我什至不需要为我想要支持的所有情况编写构造函数。这给orphanRemovel=True 带来了问题,但是哦,好吧,什么给了。
【解决方案2】:

我在这里做错了吗?

不,你不是。这就是 Hibernate 的工作原理。

如何说服 hibernate 在一个数据库调用中获取所有实体

您必须使用 HQL 或 SQL 查询来执行此操作。您不需要拥有 HBM 文件。可以通过@NamedQueries/@NamedQuery注解和list方法来完成。

网上有很多样例,比如简单的一个:

http://www.mkyong.com/hibernate/hibernate-named-query-examples/

【讨论】:

  • 我尝试了各种方法来查询它,但我无法让它工作。我将当前的原始 SQL 查询编辑到问题中。我猜这个版本在 addJoin 和名称上做错了,但也尝试了 HQL 并且总是无法在一次调用中初始化集合的集合。该链接似乎只启动了一个集合,您能否指出正确的方向,HQL/SQL 查询应该是什么样子?
  • 为此,您可能需要重新组织您的实体。可能通过在那里使用 Hibernate 组件,因为在这种查询的情况下,您必须将查询结果视为“一个非规范化表”
  • 但要做到这一点,我不仅需要更改一些代码,还需要更改实体的完整架构以及数据库,对吗?该应用程序已经在使用中,虽然您的解决方案似乎是在休眠中执行此操作的最干净的方法,但目前我不能花费太多时间和精力来重写这么多。
  • 没有必要,也根本不是数据库。也许您可以区分现有结构和查询附加结构。我的意思是从 CRUD 结构中分离搜索/选择结构。但即使使用 CRUD,Hibernate 处理一对多集合的方式也会产生开销。有时我不得不将纯 Hibernate 替换为批量语句块,这就是为什么我现在更喜欢根本不使用 Hibernate。
猜你喜欢
  • 1970-01-01
  • 2011-12-15
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 2021-01-21
相关资源
最近更新 更多