当我从数据库中选择Test2时,我可以看到单独的选择是为了得到相关的test3类的细节.这是着名的1 N选择问题.
为了解决这个问题,我使用一个select,我试图使用fetch = join注解,我明白为@Fetch(FetchMode.JOIN)
但是,随着抓取设置加入,我仍然看到单独的选择.以下是我设置的相关部分
hibernate.cfg.xml中:
<property name="max_fetch_depth">2</property>
测试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,绝望,即使它默认为EAGER OneToOne映射,但没有任何区别.
感谢任何帮助!
编辑:我几乎放弃了使用FetchMode.JOIN – 任何人都可以确认他们有工作,即生成一个左外连接?
在文档中,我看到“通常,映射文档不用于自定义提取,而是保留默认行为,并使用HQL中的左连接提取来替换特定事务”
如果我做一个左连接提取代替:
query = session.createQuery(“from 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
<?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>
测试类
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,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方式已经有更多的流量来阻止它. .?
解决方法
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.
我对另一个答案的代码非常感兴趣,因为这是我在测试您显示的代码时看到的,它从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
> 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.
如果您使用Hibernate注释因为Hibernate注释覆盖了EJB3提取选项,这不会有任何影响.见2.4.5.1. Lazy options and fetching modes.