Hibernate noob获取连接问题 [英] Hibernate noob fetch join problem

查看:110
本文介绍了Hibernate noob获取连接问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个类,Test2和Test3。 Test2有一个属性test3,它是Test3的一个实例。换句话说,我有一个单向的OneToOne关联,test2有一个对test3的引用。



当我从db中选择Test2时,可以看到单独的选择是正在获取相关test3类的详细信息。这是着名的1 + N选择问题。



为了解决这个问题,使用单个select,我尝试使用fetch = join注释,我知道它是@Fetch(FetchMode.JOIN)



但是,在提取集合加入后,我仍然可以看到单独的选择。以下是我的设置的相关部分。



hibernate.cfg.xml:

 < property name =max_fetch_depth> 2< / property> 

Test2:

  public class Test2 {
@OneToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@JoinColumn(name =test3_id)
@Fetch(FetchMode。 JOIN)
public Test3 getTest3(){
return test3;





$ b

NB我将FetchType设置为EAGER而不再绝望,即使它默认为EAGER反正OneToOne映射,但它没有区别。

感谢您的帮助!

编辑:I几乎没有放弃尝试使用FetchMode.JOIN - 任何人都可以确认他们已经得到它的工作,即产生左外连接?
在文档中,我看到通常,映射文档不用于自定义提取,而是保留默认行为,并使用HQL中的左连接提取来覆盖特定事务。



如果我做了左连接读取:



query = session.createQuery(from Test2 t2 left join fetch t2。 test3);

然后我确实得到了我想要的结果 - 即查询中的左外部连接。



编辑2:



伙计们,非常感谢您的回复。现在我想深究这一点。我通常会发现,当我调查一些东西时,最终学到的东西比我想象的要多。



我已经学会了一件事 - 因为我没有意识到maven仓库已经过时,所以我建立了hibernate。现在我已经连接到jboss存储库了,在这两种情况下,我都有最新版本的hibernate和hibernate注释 - 3.5.1-Final。



我建立了一个小测试用例,尽可能简化它 - 我仍然在3.5.1-Final中看到这个问题,我99%确定这只是我设置不正确的一些愚蠢的东西,特别是Ross,因为你已经完成了它的工作(感谢你抽出宝贵的时间来尝试)

所以我有这些课程(这次是全文)



类A

  package com.play.hibernate2; 

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

@实体
公共类A {

私人整数ID;
私人B b;

public A(){
super();
}

@Id
@GeneratedValue
public Integer getId(){
return id;
}

public void setId(Integer id){
this.id = id;

$ b $ @ @neToOne(cascade = CascadeType.ALL)
@Fetch(FetchMode.JOIN)
public B getB(){
return b;
}

public void setB(B b){
this.b = b;






B类

  package com.play.hibernate2; 

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@实体
公共类B {

私有整数id;

public B(){
super();
}

@Id
@GeneratedValue
public Integer getId(){
return id;
}

public void setId(Integer id){
this.id = id;


我的整个hibernate.cfg.xml

 <?xml version ='1.0'encoding ='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC
- // Hibernate / Hibernate配置DTD 3.0 // EN
http://hibernate.sourceforge.net/hibernate-configuration-3.0 .dtd>

< hibernate-configuration>

< session-factory>

<! - 数据库连接设置 - >
< property name =connection.driver_class> com.mysql.jdbc.Driver< / property>
<! - < property name =connection.driver_class> com.p6spy.engine.spy.P6SpyDriver< / property> - >
< property name =connection.url> jdbc:mysql:// localhost:3306 / play< / property>
< property name =connection.username> play< / property>
< property name =connection.password> play< / property>

<! - JDBC连接池(使用内置) - >
< property name =connection.pool_size> 1< / property>

<! - - SQL方言 - >
< property name =dialect> org.hibernate.dialect.MySQLDialect< / property>

<! - 启用Hibernate的自动会话上下文管理 - >
< property name =current_session_context_class>线程< / property>

<! - 禁用二级缓存 - >
< property name =cache.provider_class> org.hibernate.cache.NoCacheProvider< / property>

<! - 将所有执行的SQL回复到stdout - >
< property name =show_sql> true< / property>
< property name =generate_statistics> true< / property>
<! -
< property name =cache.use_structured_entries> true< / property>
< property name =cache.use_query_cache> true< / property>
- >
< property name =format_sql> true< / property>
< property name =use_sql_comments> true< / property>

<! - 我认为这可以解决我个人对OneToOne问题的要求 - >
< property name =max_fetch_depth> 2< / property>
<! - < property name =default_batch_fetch_size> 10< / property> - >

< / session-factory>

< / hibernate-configuration>

测试类

  package com.play.hibernate2; 

import java.util.List;
import java.util.Map;


import org.hibernate.FlushMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

public class RunTests4 {
private SessionFactory sessionFactory;

public static void main(String [] args){
RunTests4 d = new RunTests4();
d.run3();
}
public void run3(){

Session session = getSession();
session.beginTransaction();

createEntities(session);

session.getTransaction()。commit();

System.out.println(现在有新交易);
session = getSession();
session.beginTransaction();

Query query = session.createQuery(from A);
列表结果= query.list();
for(int i = 0; i< results.size(); i ++){
System.out.println(Row+ i +was:);
A a =(A)results.get(i);
System.out.println(Result+ i);
System.out.println(a.toString());
}

session.getTransaction()。commit();


$ b public void createEntities(Session session){
for(int i = 0; i <2; i ++){
A a =新的A();

B b = new B();

a.setB(b);

session.save(a);



$ public session getSession(){
if(sessionFactory == null){
AnnotationConfiguration config = new AnnotationConfiguration( );
config.addAnnotatedClass(A.class);
config.addAnnotatedClass(B.class);
config.configure();
新的SchemaExport(config).create(true,true);

sessionFactory = config.buildSessionFactory();
}
Session session = sessionFactory.getCurrentSession();

返回会话;
}

}

最后显示日志输出额外选择返回关联的类

  2 [main] INFO org.hibernate.cfg.annotations.Version  -  Hibernate Annotations 3.5 .1-Final 
23 [main] INFO org.hibernate.cfg.Environment - Hibernate 3.5.1-Final
28 [main] INFO org.hibernate.cfg.Environment - 找不到$ hibernate.properties
32 [main] INFO org.hibernate.cfg.Environment - 字节码提供程序名称:javassist
37 [main] INFO org.hibernate.cfg.Environment - 使用JDK 1.4 java.sql.Timestamp处理
160 [main] INFO org.hibernate.annotations.common.Version - Hibernate Commons Annotations 3.2.0.Final
176 [main] INFO org.hibernate.cfg.Configuration - 从资源配置:/hibernate.cfg。 xml
176 [main] INFO org.hibernate.cfg.Configuration - 配置资源:/hibernate.cfg.xml
313 [main] INFO org.hibernate.cfg.Configuration - 配置的SessionFactory:null
338 [m ain] INFO org.hibernate.dialect.Dialect - 使用方言:org.hibernate.dialect.MySQLDialect
462 [main] INFO org.hibernate.cfg.AnnotationBinder - 来自注释类的绑定实体:com.play.hibernate2。 Test2
545 [main] INFO org.hibernate.cfg.annotations.EntityBinder - 在表上绑定实体com.play.hibernate2.Test2 Test2
649 [main] INFO org.hibernate.cfg.AnnotationBinder - 绑定实体从注释类:com.play.hibernate2.Test3
650 [main] INFO org.hibernate.cfg.annotations.EntityBinder - 绑定表上的实体com.play.hibernate2.Test3 Test3
651 [main ] INFO org.hibernate.cfg.AnnotationBinder - 从注释类绑定实体:com.play.hibernate2.A
651 [main] INFO org.hibernate.cfg.annotations.EntityBinder - 绑定实体com.play.hibernate2。 A on table A
653 [main] INFO org.hibernate.cfg.AnnotationBinder - 带注释类的绑定实体:com.play.hibernate2.B
653 [main] INFO org.hibernate.cfg.annotations .EntityBinder - 绑定实体com.p lay.hibernate2.B on table B
678 [main] INFO org.hibernate.cfg.AnnotationConfiguration - 找不到Hibernate Validator:忽略
687 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - 运行hbm2ddl模式导出
688 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - 将生成的模式导出到数据库
691 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 使用内置的Hibernate )
691 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate连接池大小:1
698 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - autocommit mode:false
711 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 使用驱动程序:com.mysql.jdbc.Driver at URL:jdbc:mysql:// localhost:3306 / play
711 [ main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 连接属性:{user = play,password = ****}

alter表A
drop
外键FK412E010759

alter table Test2
drop
外键FK4CF5DC04B7E1B79

drop table if exists A

drop table如果存在B

drop table if exists Test2

drop table if exists存在Test3

create table A (
id整数不为空auto_increment,
b_id整数,
主键(id)


创建表B(
id整数不是null auto_increment,
主键(id)


创建表Test2(
id整数不为null auto_increment,
name varchar(255),
值整数不为空,
test3_id整数,
主键(id)


创建表Test3(
id integer not null auto_increment,
name varchar(255),
value integer不为null,
主键(i d)


alter table A
添加索引FK412E010759(b_id),
添加约束FK412E010759
外键(b_id)
参考B(id)

alter table Test2
add index FK4CF5DC04B7E1B79(test3_id),
add constraint FK4CF5DC04B7E1B79
foreign key(test3_id)
references Test3(id )
2562 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - 架构导出完成
2564 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 清理连接池:jdbc:mysql:/ / localhost:3306 / play
2571 [main] INFO org.hibernate.cfg.search.HibernateSearchEventListenerRegister - 无法在类路径中找到org.hibernate.search.event.FullTextIndexEventListener。休眠搜索未启用。
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 使用Hibernate内置的连接池(不用于生产使用!)
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate连接池大小:1
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 自动提交模式:false
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 使用驱动程序:com.mysql.jdbc .driver at URL:jdbc:mysql:// localhost:3306 / play
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - 连接属性:{user = play,password = ****}
2622 [main] INFO org.hibernate.cfg.SettingsFactory - RDBMS:MySQL,版本:5.1.30
2622 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC驱动程序:MySQL-AB JDBC驱动程序,版本:mysql-connector-java-5.1.9(修订版:$ {svn.Revision})
2633 [main] INFO org.hibernate.dialect.Dialect - 使用方言:org.hibernate.dialect.MySQLD ialect
2635 [main] INFO org.hibernate.engine.jdbc.JdbcSupportLoader - 禁用上下文创建LOB作为JDBC驱动程序报告JDBC版本[3]小于4
2636 [main] INFO org.hibernate.transaction .TransactionFactoryFactory - 使用默认事务策略(直接JDBC事务)
2638 [main] INFO org.hibernate.transaction.TransactionManagerLookupFactory - 没有配置TransactionManagerLookup(在JTA环境中,使用读写或事务级别的第二级缓存推荐)
2638 [main] INFO org.hibernate.cfg.SettingsFactory - beforeCompletion过程中自动刷新():已禁用
2638 [main] INFO org.hibernate.cfg.SettingsFactory - 自动会话结束时关闭事务:已禁用
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC批处理大小:15
2638 [main] INFO org.hibernate.cfg.SettingsFactory - 版本化数据的JDBC批更新:已禁用
2638 [main] INFO org.hibernate.cfg.SettingsFactory - 可滚动结果sets:enabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC3 getGeneratedKeys():enabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - 连接发布模式:auto
2639 [main] INFO org.hibernate.cfg.SettingsFactory - 最大外部连接获取深度:2
2639 [main] INFO org.hibernate.cfg.SettingsFactory - 默认批量获取大小:1
2639 [main] INFO org.hibernate.cfg.SettingsFactory - 使用注释生成SQL:
2639 [main] INFO org.hibernate.cfg.SettingsFactory - 按主键排序SQL更新:disabled
2639 [main ] INFO org.hibernate.cfg.SettingsFactory - 用于批处理的订单SQL插入:已禁用
2639 [main] INFO org.hibernate.cfg.SettingsFactory - 查询转换器:org.hibernate.hql.ast.ASTQueryTranslatorFactory
2641 [main] INFO org.hibernate.hql.ast.ASTQueryTranslatorFactory - 使用ASTQueryTranslatorFactory
2641 [main] INFO org.hibernate.cfg.SettingsFactory - 查询语言替换:{}
2641 [main ] INFO org.hibernate.cfg.SettingsFactory - JPA-QL严格遵从性:已禁用
2641 [main] INFO org.hibernate.cfg.SettingsFactory - 二级缓存:已启用
2641 [main] INFO org .hibernate.cfg.SettingsFactory - 查询缓存:已禁用
2644 [main] INFO org.hibernate.cfg.SettingsFactory - 缓存区域工厂:org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge
2644 [main ] INFO org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge - 缓存提供程序:org.hibernate.cache.NoCacheProvider
2644 [main] INFO org.hibernate.cfg.SettingsFactory - 为最小放置优化缓存:disabled
2644 [main] INFO org.hibernate.cfg.SettingsFactory - 结构化的二级缓存条目:已禁用
2648 [main] INFO org.hibernate.cfg.SettingsFactory - 将所有SQL回送到标准输出
2648 [main] INFO org.hibernate.cfg.SettingsFactory - 统计:启用
2649 [main] INFO org.hibernate.cfg.SettingsFactory - 删除的实体合成标识符rollbac k:disabled
2649 [main] INFO org.hibernate.cfg.SettingsFactory - 默认实体模式:pojo
2649 [main] INFO org.hibernate.cfg.SettingsFactory - 命名查询检查:启用
2649 [main] INFO org.hibernate.cfg.SettingsFactory - 检查核心中的可空性(当Bean Validation打开时应该禁用):enabled
2697 [main] INFO org.hibernate.impl.SessionFactoryImpl - 构建会话工厂
2796 [Finalizer] INFO org.hibernate.connection.DriverManagerConnectionProvider - 清理连接池:jdbc:mysql:// localhost:3306 / play
2929 [main] INFO org.hibernate.impl.SessionFactoryObjectFactory - 不绑定工厂到JNDI,没有配置JNDI名称
Hibernate:
/ * insert com.play.hibernate2.B
* / insert
into
B


()
Hibernate:
/ * insert com.play.hibernate2.A
* / insert
into
A
(b_id)

(?)
Hibernate:
/ * insert com.play.hibernate2.B
* / insert
into
B


()
Hibernate:
/ * insert com.play.hibernate2.A
* / insert
into
A
(b_id)

(?)
现在有一个新的事务
Hibernate:
/ *
from
A * / select
a0_.id as id2_,
a0_.b_id as b2_2_
from
A a0_
Hibernate:
/ * load com.play.hibernate2.B * / select
b0_.id as id3_0_
from
B b0_
where
b0_.id =?
Hibernate:
/ * load com.play.hibernate2.B * / select
b0_.id as id3_0_
from
B b0_
where
b0_.id =?
第0行是:
结果0
com.play.hibernate2.A@351daa0e
第1行是:
结果1
com.play.hibernate2 .A @ 2e879860

编辑3:

如果我用罗斯的方式做事,加载时会创建一个左外连接。如果我用一个列表来做,就会发出单独的选择。这是相关的代码。
$ b

  / *生成左外连接
A a =(A) session.load(的A.class,1);
System.out.println(a.getId()+=+ a.getB()。getName());
* /

//为每个对象b创建单独的选项b
Query query = session.createQuery(from A);
列表结果= query.list();
A a =(A)results.get(0);
System.out.println(a.getId()+=+ a.getB()。getName());

我猜它可能被称为'错误'。正如我前面提到的,在文档中,他们说在HQL中而不是在映射中指定获取模式是'平常的',我认为这可能意味着HQL方式已经有更多的人流量来处理它。 。
$ b

(顺便说,我为A和B添加了一个额外的'name'字段,否则hibernate会优化检索,因为它可以从外键获取所有B在A中)

解决方案


当我从db中选择Test2时,我可以看到一个单独的选择是为了获得相关test3类的细节。


我对其他答案的代码非常感兴趣,因为这是当我测试你显示的代码时,我也看到了它,它为Test2 中的生成两个选择。



我使用以下依赖项:


  • org.hibernate:hibernate -entitymanager:jar:3.4.0.GA:compile

  • org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile

  • org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile

  • org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile
  • li>
  • org.hibernate:hibernate-core:jar:3.3.0.SP1:compile




我将FetchType置于EAGER之外,即使OneToOne映射默认为EAGER,但它没有区别。

如果使用Hibernate注释,则这没有影响,因为Hibernate注释会覆盖EJB3抓取选项。请参阅 2.4.5.1。懒惰选项和抓取模式


I have two classes, Test2 and Test3. Test2 has an attribute test3 that is an instance of Test3. In other words, I have a unidirectional OneToOne association, with test2 having a reference to test3.

When I select Test2 from the db, I can see that a separate select is being made to get the details of the associated test3 class. This is the famous 1+N selects problem.

To fix this to use a single select, I am trying to use the fetch=join annotation, which I understand to be @Fetch(FetchMode.JOIN)

However, with fetch set to join, I still see separate selects. Here are the relevant portions of my setup..

hibernate.cfg.xml:

<property name="max_fetch_depth">2</property>

Test2:

public class Test2 {
 @OneToOne (cascade=CascadeType.ALL , fetch=FetchType.EAGER)
 @JoinColumn (name="test3_id")
 @Fetch(FetchMode.JOIN)
 public Test3 getTest3() {
  return test3;
}

NB I set the FetchType to EAGER out of desperation, even though it defaults to EAGER anyway for OneToOne mappings, but it made no difference.

Thanks for any help!

Edit: I've pretty much given up on trying to use FetchMode.JOIN - can anyone confirm that they have got it to work ie produce a left outer join? In the docs I see that "Usually, the mapping document is not used to customize fetching. Instead, we keep the default behavior, and override it for a particular transaction, using left join fetch in HQL"

If I do a left join fetch instead:

query = session.createQuery("from Test2 t2 left join fetch t2.test3");

then I do indeed get the results I want - ie a left outer join in the query.

Edit number 2:

Guys, thank you so much for your responses. Now I want to get to the bottom of this. I usually find that when I investigate something, I end up learning a lot more than I thought I would.

One thing I've learned already - I was running on old builds of hibernate because I didn't realize that the maven repository was out of date. Now I'm hooked up to the jboss repository too, and I have the latest versions of hibernate and hibernate annotations - 3.5.1-Final in both cases.

I've set up a small test case that simplifies it as much as I can - I'm still seeing the problem in 3.5.1-Final, tho' I'm 99% certain it's just something stupid I'm not setting up right, especially Ross, given that you got it to work (thanks for taking the time to try it by the way)

So I have these classes (full text this time)

Class A

package com.play.hibernate2;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

@Entity
public class A {

    private Integer id;
    private B b;

    public A() {
        super();
    }

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @OneToOne (cascade=CascadeType.ALL)
    @Fetch(FetchMode.JOIN)
    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }
}

Class B

package com.play.hibernate2;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class B {

    private Integer id;

    public B() {
        super();
    }

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }   
}

My whole hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- <property name="connection.driver_class">com.p6spy.engine.spy.P6SpyDriver</property> -->
        <property name="connection.url">jdbc:mysql://localhost:3306/play</property>
        <property name="connection.username">play</property>
        <property name="connection.password">play</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
        <property name="generate_statistics">true</property>
        <!--
        <property name="cache.use_structured_entries">true</property>
        <property name="cache.use_query_cache">true</property>
        -->
        <property name="format_sql">true</property>
        <property name="use_sql_comments">true</property>

        <!-- I think this may fix my individual requests for OneToOne problem -->
        <property name="max_fetch_depth">2</property>
        <!-- <property name="default_batch_fetch_size">10</property> -->

    </session-factory>    

</hibernate-configuration>

The testing class

package com.play.hibernate2;

import java.util.List;
import java.util.Map;


import org.hibernate.FlushMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

public class RunTests4 {
    private SessionFactory sessionFactory;

    public static void main(String[] args){
        RunTests4 d = new RunTests4();
        d.run3();
    }
    public void run3(){

        Session session = getSession();
        session.beginTransaction();

        createEntities(session);

        session.getTransaction().commit();

        System.out.println("NOW WITH A NEW TRANSACTION");
        session = getSession();
        session.beginTransaction();

        Query query = session.createQuery("from A");
        List results = query.list();
        for (int i=0; i<results.size(); i++){
            System.out.println("Row "+i+" was:");
            A a = (A)results.get(i);
            System.out.println("Result "+i);
            System.out.println(a.toString());
        }

        session.getTransaction().commit();


    }
    public void createEntities(Session session){
        for (int i=0; i<2; i++){
            A a = new A();

            B b = new B();

            a.setB(b);

            session.save(a);

        }

    }
    public Session getSession(){
        if (sessionFactory == null){
            AnnotationConfiguration config = new AnnotationConfiguration();
            config.addAnnotatedClass(A.class);
            config.addAnnotatedClass(B.class);
            config.configure();
            new SchemaExport(config).create(true,true);

            sessionFactory = config.buildSessionFactory();
        }
        Session session = sessionFactory.getCurrentSession();

        return session;
    }

}

And finally the log output showing the extra selects to get back the associated class

2 [main] INFO org.hibernate.cfg.annotations.Version - Hibernate Annotations 3.5.1-Final
23 [main] INFO org.hibernate.cfg.Environment - Hibernate 3.5.1-Final
28 [main] INFO org.hibernate.cfg.Environment - hibernate.properties not found
32 [main] INFO org.hibernate.cfg.Environment - Bytecode provider name : javassist
37 [main] INFO org.hibernate.cfg.Environment - using JDK 1.4 java.sql.Timestamp handling
160 [main] INFO org.hibernate.annotations.common.Version - Hibernate Commons Annotations 3.2.0.Final
176 [main] INFO org.hibernate.cfg.Configuration - configuring from resource: /hibernate.cfg.xml
176 [main] INFO org.hibernate.cfg.Configuration - Configuration resource: /hibernate.cfg.xml
313 [main] INFO org.hibernate.cfg.Configuration - Configured SessionFactory: null
338 [main] INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.MySQLDialect
462 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.Test2
545 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.Test2 on table Test2
649 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.Test3
650 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.Test3 on table Test3
651 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.A
651 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.A on table A
653 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.B
653 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.B on table B
678 [main] INFO org.hibernate.cfg.AnnotationConfiguration - Hibernate Validator not found: ignoring
687 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - Running hbm2ddl schema export
688 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - exporting generated schema to database
691 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Using Hibernate built-in connection pool (not for production use!)
691 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate connection pool size: 1
698 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - autocommit mode: false
711 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/play
711 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - connection properties: {user=play, password=****}

    alter table A 
        drop 
        foreign key FK412E010759

    alter table Test2 
        drop 
        foreign key FK4CF5DC04B7E1B79

    drop table if exists A

    drop table if exists B

    drop table if exists Test2

    drop table if exists Test3

    create table A (
        id integer not null auto_increment,
        b_id integer,
        primary key (id)
    )

    create table B (
        id integer not null auto_increment,
        primary key (id)
    )

    create table Test2 (
        id integer not null auto_increment,
        name varchar(255),
        value integer not null,
        test3_id integer,
        primary key (id)
    )

    create table Test3 (
        id integer not null auto_increment,
        name varchar(255),
        value integer not null,
        primary key (id)
    )

    alter table A 
        add index FK412E010759 (b_id), 
        add constraint FK412E010759 
        foreign key (b_id) 
        references B (id)

    alter table Test2 
        add index FK4CF5DC04B7E1B79 (test3_id), 
        add constraint FK4CF5DC04B7E1B79 
        foreign key (test3_id) 
        references Test3 (id)
2562 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - schema export complete
2564 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - cleaning up connection pool: jdbc:mysql://localhost:3306/play
2571 [main] INFO org.hibernate.cfg.search.HibernateSearchEventListenerRegister - Unable to find org.hibernate.search.event.FullTextIndexEventListener on the classpath. Hibernate Search is not enabled.
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Using Hibernate built-in connection pool (not for production use!)
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate connection pool size: 1
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - autocommit mode: false
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/play
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - connection properties: {user=play, password=****}
2622 [main] INFO org.hibernate.cfg.SettingsFactory - RDBMS: MySQL, version: 5.1.30
2622 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.1.9 ( Revision: ${svn.Revision} )
2633 [main] INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.MySQLDialect
2635 [main] INFO org.hibernate.engine.jdbc.JdbcSupportLoader - Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
2636 [main] INFO org.hibernate.transaction.TransactionFactoryFactory - Using default transaction strategy (direct JDBC transactions)
2638 [main] INFO org.hibernate.transaction.TransactionManagerLookupFactory - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Automatic flush during beforeCompletion(): disabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Automatic session close at end of transaction: disabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC batch size: 15
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC batch updates for versioned data: disabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Scrollable result sets: enabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC3 getGeneratedKeys(): enabled
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Connection release mode: auto
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Maximum outer join fetch depth: 2
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Default batch fetch size: 1
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Generate SQL with comments: enabled
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Order SQL updates by primary key: disabled
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Order SQL inserts for batching: disabled
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
2641 [main] INFO org.hibernate.hql.ast.ASTQueryTranslatorFactory - Using ASTQueryTranslatorFactory
2641 [main] INFO org.hibernate.cfg.SettingsFactory - Query language substitutions: {}
2641 [main] INFO org.hibernate.cfg.SettingsFactory - JPA-QL strict compliance: disabled
2641 [main] INFO org.hibernate.cfg.SettingsFactory - Second-level cache: enabled
2641 [main] INFO org.hibernate.cfg.SettingsFactory - Query cache: disabled
2644 [main] INFO org.hibernate.cfg.SettingsFactory - Cache region factory : org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge
2644 [main] INFO org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge - Cache provider: org.hibernate.cache.NoCacheProvider
2644 [main] INFO org.hibernate.cfg.SettingsFactory - Optimize cache for minimal puts: disabled
2644 [main] INFO org.hibernate.cfg.SettingsFactory - Structured second-level cache entries: disabled
2648 [main] INFO org.hibernate.cfg.SettingsFactory - Echoing all SQL to stdout
2648 [main] INFO org.hibernate.cfg.SettingsFactory - Statistics: enabled
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Deleted entity synthetic identifier rollback: disabled
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Default entity-mode: pojo
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Named query checking : enabled
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Check Nullability in Core (should be disabled when Bean Validation is on): enabled
2697 [main] INFO org.hibernate.impl.SessionFactoryImpl - building session factory
2796 [Finalizer] INFO org.hibernate.connection.DriverManagerConnectionProvider - cleaning up connection pool: jdbc:mysql://localhost:3306/play
2929 [main] INFO org.hibernate.impl.SessionFactoryObjectFactory - Not binding factory to JNDI, no JNDI name configured
Hibernate: 
    /* insert com.play.hibernate2.B
        */ insert 
        into
            B

        values
            ( )
Hibernate: 
    /* insert com.play.hibernate2.A
        */ insert 
        into
            A
            (b_id) 
        values
            (?)
Hibernate: 
    /* insert com.play.hibernate2.B
        */ insert 
        into
            B

        values
            ( )
Hibernate: 
    /* insert com.play.hibernate2.A
        */ insert 
        into
            A
            (b_id) 
        values
            (?)
NOW WITH A NEW TRANSACTION
Hibernate: 
    /* 
from
    A */ select
        a0_.id as id2_,
        a0_.b_id as b2_2_ 
    from
        A a0_
Hibernate: 
    /* load com.play.hibernate2.B */ select
        b0_.id as id3_0_ 
    from
        B b0_ 
    where
        b0_.id=?
Hibernate: 
    /* load com.play.hibernate2.B */ select
        b0_.id as id3_0_ 
    from
        B b0_ 
    where
        b0_.id=?
Row 0 was:
Result 0
com.play.hibernate2.A@351daa0e
Row 1 was:
Result 1
com.play.hibernate2.A@2e879860

Edit Number 3:

If I do things Ross' way, with a load, a left outer join gets created. If I do it with a list, separate selects are issued. Here's the relevant code. Only changing this reproduces the difference in behavior:

    /* generates the left outer join
    A a = (A)session.load(A.class,1);
    System.out.println(a.getId()+" = "+a.getB().getName());
    */

    // Creates separate selects for each object b associated with each a
    Query query = session.createQuery("from A");
    List results = query.list();
    A a = (A)results.get(0);
    System.out.println(a.getId()+" = "+a.getB().getName());

I guess it might be called a 'bug'. As I mentioned earlier, in the docs, they say it's 'usual' to specify the fetch mode in the HQL rather than in the mapping, which I'm thinking might mean that the HQL way has had more foot traffic to bed it down..?

(by the way I added an extra 'name' field to A and B otherwise hibernate optimizes the retrieve because it can get all of B just from the foreign key on A)

解决方案

When I select Test2 from the db, I can see that a separate select is being made to get the details of the associated test3 class.

I'm very interested by the code of the other answer because that's what I'm seeing too when testing the code you're showing, it generates two selects for a from Test2.

I'm using the following dependencies:

  • org.hibernate:hibernate-entitymanager:jar:3.4.0.GA:compile
  • org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile
  • org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile
  • org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile
  • org.hibernate:hibernate-core:jar:3.3.0.SP1:compile

I set the FetchType to EAGER out of desperation, even though it defaults to EAGER anyway for OneToOne mappings, but it made no difference.

This has no impact if you use Hibernate annotations because the Hibernate annotations overrides the EJB3 fetching options. See 2.4.5.1. Lazy options and fetching modes.

这篇关于Hibernate noob获取连接问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆