Hibernate noob获取连接问题

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

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

要修复此问题以使用单个选择,我尝试使用fetch = join批注,我理解为@Fetch(FetchMode.JOIN)

但是,如果将fetch设置为join,我仍会看到单独的选择。 以下是我的设置的相关部分..

hibernate.cfg.xml中:

2 

测试2:

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

NB我将FetchType设置为EAGER绝望,即使它默认为OneAGoOne映射的EAGER,但它没有任何区别。

谢谢你的帮助!

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

如果我做一个左连接提取而是:

query = session.createQuery(“来自Test2 t2 left join fetch t2.test3”);

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

编辑2:

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

我已经学到了一件事 – 我正在运行旧版本的hibernate,因为我没有意识到maven存储库已经过时了。 现在我也连接到jboss存储库,我有最新版本的hibernate和hibernate注释 – 在两种情况下都是3.5.1-Final。

我已经设置了一个小的测试用例,尽可能地简化了它 – 我仍然在3.5.1-Final中看到问题,因为’我99%肯定这只是一些愚蠢我没有设置是的,特别是罗斯,因为你得到它的工作(感谢花时间尝试顺便说一句)

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

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; } } 

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; } } 

我的整个hibernate.cfg.xml

      com.mysql.jdbc.Driver <!-- com.p6spy.engine.spy.P6SpyDriver --> jdbc:mysql://localhost:3306/play play play  1  org.hibernate.dialect.MySQLDialect  thread  org.hibernate.cache.NoCacheProvider  true true <!-- true true --> true true  2 <!-- 10 -->   

测试类

 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; } } 

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

 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 

编辑3:

如果我按照罗斯的方式做事,加载时会创建一个左外连接。 如果我使用列表执行此操作,则会发出单独的选择。 这是相关的代码。 只有改变它才能重现行为上的差异:

  /* 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()); 

我猜它可能被称为’bug’。 正如我之前提到的,在文档中,他们说在HQL中而不是在映射中指定获取模式是“通常的”,我认为这可能意味着HQL方式有更多的人流量来降低它。 。?

(顺便说一下,我给A和B添加了一个额外的’name’字段,否则hibernate优化了检索,因为它可以从A上的外键获得所有B)

当我从db中选择Test2时,我可以看到正在进行单独的选择以获取相关test3类的详细信息。

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

我正在使用以下依赖项:

  • org.hibernate作为:hibernate-的EntityManager:jar子:3.4.0.GA:编译
  • org.hibernate作为:EJB3持久性:jar子:1.0.2.GA:编译
  • org.hibernate作为:冬眠公地的注解:jar子:3.1.0.GA:编译
  • org.hibernate作为:冬眠的注解:jar子:3.4.0.GA:编译
  • org.hibernate作为:hibernate核心:jar子:3.3.0.SP1:编译

我将FetchType设置为绝望,尽管对于OneToOne映射它无论如何都默认为EAGER,但它没有任何区别。

如果使用Hibernate注释,这没有任何影响,因为Hibernate注释会覆盖EJB3提取选项。 见2.4.5.1。 懒惰选项和提取模式 。

作为蒸馏:

如果使用Query接口(例如:session.createQuery()),将忽略@Fetch(JOIN),但如果使用Criteria接口,它将被正确使用。

这实际上是Hibernate中一个从未解决的错误。 很不幸,因为许多应用程序使用Query接口,无法轻松迁移到Criteria接口。

如果使用Query接口,则必须手动将JOIN FETCH语句添加到HQL中。

我创建了一个非常简单的应用程序来测试你得到的场景,你的代码应该工作(它对我有用)。 我尝试过的唯一能给我多个select语句的是将max_fetch_depth设置为0.如果设置为2(或未配置),我在查询中得到左外连接。 您使用的是什么版本的hibernate? 我使用的是3.4.0.GA.

编辑:下面是我使用的简单应用程序(与Pascal提到的相同版本):

CFG:

   org.hsqldb.jdbcDriver jdbc:hsqldb:hibscribs sa  org.hibernate.dialect.HSQLDialect true true create-drop thread      

人物实体 – 保持简单只有@OneToOne,添加JoinColumn等没有区别。

 @Entity @Table(name="person") public class Person { private Long id; private String name; private Phone phone; @Id public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToOne(cascade=CascadeType.ALL) public Phone getPhone() { return phone; } public void setPhone(Phone phone) { this.phone = phone; } } 

 @Entity @Table(name="phone") public class Phone { private Long id; private String number; @Id public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } } 

简单测试:

 SessionFactory session = HibernateUtil.getSessionFactory(); Session sess = session.getCurrentSession(); Transaction tx = sess.beginTransaction(); Phone phone = new Phone(); phone.setId(1L); phone.setNumber("1234567"); Person person = new Person(); person.setId(1L); person.setName("Bob"); person.setPhone(phone); sess.save(person); tx.commit(); sess = session.openSession(); //Person p1 = (Person)sess.load(Person.class,1L); //System.out.println(p1.getPhone().getNumber()); // changed the above code to use the Criteria interface below: Criteria criteria = sess.createCriteria(Person.class); List results = criteria.list(); for (int i=0; i 

输出:

 Hibernate: select phone_.id, phone_.number as number1_ from phone phone_ where phone_.id=? Hibernate: insert into phone (number, id) values (?, ?) Hibernate: insert into person (name, phone_id, id) values (?, ?, ?) Hibernate: select person0_.id as id0_1_, person0_.name as name0_1_, person0_.phone_id as phone3_0_1_, phone1_.id as id1_0_, phone1_.number as number1_0_ from person person0_ left outer join phone phone1_ on person0_.phone_id=phone1_.id where person0_.id=? 1234567