有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernate即时加载(获取所有属性不起作用)

基本上我想加载属性。我有以下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>

编辑2:

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

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

共 (3) 个答案

  1. # 1 楼答案

    看起来它无法通过单独的列在单个查询中检索obj

    由于对其他列使用了相同的User值,@axtavt中的示例似乎是最好的解决方案

  2. # 2 楼答案

    问题在于.iterate()。根据Hibernate API docs

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

    这是一个特殊的函数,当我们希望生成的对象已被缓存时使用。当被访问时,它们将被(延迟)加载

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

    谢谢你的帮助

  3. # 3 楼答案

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

    我认为最好做一个简单的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;
            }
        });