Hibernate 预加载(获取所有属性不起作用)

发布于 2024-11-01 17:50:01 字数 3200 浏览 2 评论 0原文

基本上我想立即加载属性。我有以下 HQL 查询:

SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties

我希望它只执行一个查询。相反,我收到了 N+1 个查询。

代码如下:

Query q = mySession.createQuery(
    "SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties")
    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

for (Iterator i = q.iterate(); i.hasNext();) {
    Object line = i.next();
    System.out.println(line);
}

我得到的输出(将 hibernate.show_sql 设置为 true)是:

Hibernate: select user0_.id as col_0_0_, user0_.name as col_1_0_, user0_.id as col_2_0_ from user user0_
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=1, obj=User@b6548 [id='1' name='John' ], text=John}
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=2, obj=User@4865ce [id='2' name='Arnold' ], text=Arnold}

Ps:没有变压器时情况是一样的嗯>。


编辑:

带有实体映射的文件:

<hibernate-mapping>
    
    <class name="User" table="user">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="location"/>
        <map name="customPrices" table="custprice">
            <key column="user"/>
            <map-key-many-to-many column="product" class="Product"/>
            <element column="price" type="double"/>
        </map>
    </class>
    
    <class name="Product" table="product">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="listprice"/>
    </class>
    
</hibernate-mapping>

我尝试将 lazy="false" 添加到类和各个属性中。没有区别。

我的配置文件:

<hibernate-configuration>
<session-factory>
    <property name="connection.url">jdbc:mysql://192.168.0.203/hibtest</property>
    <property name="connection.username">hibtest</property>
    <property name="connection.password">hibb345</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <property name="current_session_context_class">thread</property>
    <property name="hibernate.show_sql">true</property>
    
    <mapping resource="combined.hbm.xml" />
</session-factory> 
</hibernate-configuration>

Edit2:

即使下面的代码也会导致N+1查询。虽然我只获取 ID 字段,但根据文档,这不应导致对象加载。

for (Iterator i = q.iterate(); i.hasNext();) {
    Object line = i.next();
    User u = (User)((Map)line).get("obj");
    System.out.println(u.getId());
}

Basically I want to eager-load properties. I have the following HQL query:

SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties

I would expect this to execute one query only. Instead I got N+1 queries.

The code is the following:

Query q = mySession.createQuery(
    "SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties")
    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

for (Iterator i = q.iterate(); i.hasNext();) {
    Object line = i.next();
    System.out.println(line);
}

The output I get (with hibernate.show_sql set to true) is:

Hibernate: select user0_.id as col_0_0_, user0_.name as col_1_0_, user0_.id as col_2_0_ from user user0_
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=1, obj=User@b6548 [id='1' name='John' ], text=John}
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=2, obj=User@4865ce [id='2' name='Arnold' ], text=Arnold}

Ps: The situation is just the same without transformers.


Edit:

The file with the entity-mappings:

<hibernate-mapping>
    
    <class name="User" table="user">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="location"/>
        <map name="customPrices" table="custprice">
            <key column="user"/>
            <map-key-many-to-many column="product" class="Product"/>
            <element column="price" type="double"/>
        </map>
    </class>
    
    <class name="Product" table="product">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="listprice"/>
    </class>
    
</hibernate-mapping>

I tried adding lazy="false" to the class and to the individual properties. No difference.

My configuration file:

<hibernate-configuration>
<session-factory>
    <property name="connection.url">jdbc:mysql://192.168.0.203/hibtest</property>
    <property name="connection.username">hibtest</property>
    <property name="connection.password">hibb345</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <property name="current_session_context_class">thread</property>
    <property name="hibernate.show_sql">true</property>
    
    <mapping resource="combined.hbm.xml" />
</session-factory> 
</hibernate-configuration>

Edit2:

Even the following code causes N+1 query. Although I only fetch the ID field, which according to documentation should not cause objects to load.

for (Iterator i = q.iterate(); i.hasNext();) {
    Object line = i.next();
    User u = (User)((Map)line).get("obj");
    System.out.println(u.getId());
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

子栖 2024-11-08 17:50:01

问题出在 .iterate() 上。根据 Hibernate API 文档< /a>:

作为结果返回的实体根据需要进行初始化。第一个 SQL 查询仅返回标识符。

这是一个特殊函数,当我们期望结果对象已经缓存时使用。它们在访问时将被(延迟)加载。

因此,对于一般用途,要获取查询结果的迭代器,您应该使用 .list().iterate()

感谢 Eran Harel 的帮助。

The problem was with .iterate(). According to Hibernate API docs:

Entities returned as results are initialized on demand. The first SQL query returns identifiers only.

This is a special function to be used when we expect the resulting objects to be already cached. They will be (lazy) loaded when accessed.

So for general use, to get an iterator on a result of a query you should use .list().iterate().

Thanks for Eran Harel for the help.

可是我不能没有你 2024-11-08 17:50:01

从本质上讲,问题的原因是尝试将结果转换逻辑合并到查询中。

我认为最好做一个简单的 HQL 查询,然后在自定义 ResultTransformer 中应用特定的结果转换逻辑,如下所示:

Query q = mySession.createQuery("FROM User")
    .setResultTransformer(new ResultTransformer() {
        public List transformList(List l) { return l; }
        public Object transformTuple(Object[] tuple, String[] aliases) {
            Map<String, Object> r = new HashMap<String, Object>();
            User u = (User) tuple[0];
            r.put("obj", u);
            r.put("id", u.getId());
            r.put("text", u.getName());
            return r;
        }
    }); 

In essense, the cause of your problem is an attempt to incorporate result transformation logic into a query.

I think it would be better to make a simple HQL query and then apply your specific result transformation logic in a custom ResultTransformer, something like this:

Query q = mySession.createQuery("FROM User")
    .setResultTransformer(new ResultTransformer() {
        public List transformList(List l) { return l; }
        public Object transformTuple(Object[] tuple, String[] aliases) {
            Map<String, Object> r = new HashMap<String, Object>();
            User u = (User) tuple[0];
            r.put("obj", u);
            r.put("id", u.getId());
            r.put("text", u.getName());
            return r;
        }
    }); 
去了角落 2024-11-08 17:50:01

看起来它无法在具有单独列的单个查询中检索 obj。

由于您对其他列使用来自 User 的相同值,因此 @axtavt 中的示例似乎是您的最佳解决方案。

Looks like it cannot retrieve the obj in a single query with separate columns.

Since you use the same values from User for the other columns, the example from @axtavt seems your best solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文