-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: Lazy loading ManyToOne relationships?
PostPosted: Sun Jun 10, 2007 2:41 pm 
Beginner
Beginner

Joined: Tue Nov 29, 2005 4:42 pm
Posts: 49
Location: Atlanta, GA
I have a ManyToOne relationship that I want to load lazily. I've read the documentation over and over, and I know that ManyToOne are marked Eager by default. So I've set this to lazy like:

Code:
    @ManyToOne( cascade = CascadeType.PERSIST, fetch = FetchType.LAZY )
    @JoinColumn( name="BINARY_DATA_ID" )
    @JSON( include = false )
    public BinaryData getMessage() {
        return message;
    }

    public void setMessage(BinaryData message) {
        this.message = message;
    }


But I keep getting the following showing up in my logs.

Code:
    select
        binarydata0_.id as id2_0_,
        binarydata0_.data as data2_0_
    from
        APP.BINARYDATA binarydata0_
    where
        binarydata0_.id=?



This is the original query I submit that causes the query above:

Code:
    select
        messageent0_.ID as ID0_1_,
        messageent0_.MESSAGE_BCC as MESSAGE2_0_1_,
        messageent0_.MESSAGE_CC as MESSAGE3_0_1_,
        messageent0_.CONTENT_TYPE as CONTENT4_0_1_,
        messageent0_.MESSAGE_DATE as MESSAGE5_0_1_,
        messageent0_.DISPLAY_TEXT as DISPLAY6_0_1_,
        messageent0_.MESSAGE_FROM as MESSAGE7_0_1_,
        messageent0_.BINARY_DATA_ID as BINARY12_0_1_,
        messageent0_.MESSAGE_ID as MESSAGE8_0_1_,
        messageent0_.SEARCH_TEXT as SEARCH9_0_1_,
        messageent0_.MESSAGE_SUBJECT as MESSAGE10_0_1_,
        messageent0_.MESSAGE_TO as MESSAGE11_0_1_,
        attachment1_.MESSAGE_ID as MESSAGE6_3_,
        attachment1_.ID as ID3_,
        attachment1_.ID as ID1_0_,
        attachment1_.ATTACHMENT_FILE as ATTACHMENT2_1_0_,
        attachment1_.ATTACHMENT_NAME as ATTACHMENT3_1_0_,
        attachment1_.inline as inline1_0_,
        attachment1_.MESSAGE_ID as MESSAGE6_1_0_,
        attachment1_.CONTENT_TYPE as CONTENT5_1_0_
    from
        APP.MESSAGES messageent0_
    left outer join
        APP.ATTACHMENTS attachment1_
            on messageent0_.ID=attachment1_.MESSAGE_ID
    where
        messageent0_.ID=?


This query is correct, but for some reason it keeps wanting to load the the getMessages(). I've tried everything I could think of, but it just doesn't want to be lazy.

What am I doing incorrectly? I'm banging my head against this one. Please help.

Charlie


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 10, 2007 3:15 pm 
Beginner
Beginner

Joined: Tue Nov 29, 2005 4:42 pm
Posts: 49
Location: Atlanta, GA
Here is some debug output from hibernate I thought that might help. This is another ManyToOne relationship I want to load lazily. However, it's loading it eagerly everytime. I thought it was interesting since it does what I wanted then the TwoPhaseLoad class kicks in and starts trying to load the rest of the relationships.

I can't for the life of me figure out why this TwoPhasedLoad is listening and loading these relationships.

In this case AttachmentEntity has a bidirectional ManyToOne with MessageEntity. MessageEntity has a OneToMany with AttachementEntity that is loaded eagerly. In this log I'm trying to just load the AttachmentEntity, but the MessageEntity is loading as well. Eventhough I've marked the relationship as lazy.

This is really affecting performance in my app.

Code:
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.impl.SessionImpl  - opened session at timestamp: 11815011625
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.transaction.JDBCTransaction  - begin
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.ConnectionManager  - opening JDBC connection
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource  - Creating new JDBC Connection to [jdbc:derby:emailarchive]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.transaction.JDBCTransaction  - current autocommit status: true
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.transaction.JDBCTransaction  - disabling autocommit
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.JDBCContext  - after transaction begin
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.engine.query.QueryPlanCache  - located HQL query plan in cache (from AttachmentEntity where id = ? )
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.engine.query.QueryPlanCache  - located HQL query plan in cache (from AttachmentEntity where id = ? )
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.engine.query.HQLQueryPlan  - find: from AttachmentEntity where id = ?
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.engine.QueryParameters  - parameters: [7]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.engine.QueryParameters  - named parameters: {}
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.SQL  -
    select
        attachment0_.ID as ID1_,
        attachment0_.ATTACHMENT_FILE as ATTACHMENT2_1_,
        attachment0_.ATTACHMENT_NAME as ATTACHMENT3_1_,
        attachment0_.inline as inline1_,
        attachment0_.MESSAGE_ID as MESSAGE6_1_,
        attachment0_.CONTENT_TYPE as CONTENT5_1_
    from
        APP.ATTACHMENTS attachment0_
    where
        attachment0_.ID=?
Hibernate:
    select
        attachment0_.ID as ID1_,
        attachment0_.ATTACHMENT_FILE as ATTACHMENT2_1_,
        attachment0_.ATTACHMENT_NAME as ATTACHMENT3_1_,
        attachment0_.inline as inline1_,
        attachment0_.MESSAGE_ID as MESSAGE6_1_,
        attachment0_.CONTENT_TYPE as CONTENT5_1_
    from
        APP.ATTACHMENTS attachment0_
    where
        attachment0_.ID=?
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - preparing statement
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.IntegerType  - binding '7' to parameter: 1
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to open ResultSet (open ResultSets: 0, globally: 0)
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - processing result set
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - result set row: 0
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.IntegerType  - returning '7' as column: ID1_
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - result row: EntityKey[com.emailarchive.entity.AttachmentEntity#7]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - Initializing object from ResultSet: [com.emailarchive.entity.AttachmentEntity#7]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.persister.entity.AbstractEntityPersister  - Hydrating entity: [com.emailarchive.entity.AttachmentEntity#7]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.StringType  - returning 'D:\dev\src\emailarchive\server\data\data21041.gif' as column: ATTACHMENT2_1_
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.StringType  - returning 'who-broke-the-build.gif' as column: ATTACHMENT3_1_
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.BooleanType  - returning 'false' as column: inline1_
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.IntegerType  - returning '146' as column: MESSAGE6_1_
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.type.StringType  - returning 'image/gif; name=who-broke-the-build.gif' as column: CONTENT5_1_
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - done processing result set (1 rows)
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to close ResultSet (open ResultSets: 1, globally: 1)
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - closing statement
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - total objects hydrated: 1
----------------HERE IS THE TWO PHASE LOAD KICKING IN-------------
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.engine.TwoPhaseLoad  - resolving associations for [com.emailarchive.entity.AttachmentEntity#7]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.event.def.DefaultLoadEventListener  - loading entity: [com.emailarchive.entity.MessageEntity#146]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.event.def.DefaultLoadEventListener  - attempting to resolve: [com.emailarchive.entity.MessageEntity#146]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.event.def.DefaultLoadEventListener  - object not resolved in any cache: [com.emailarchive.entity.MessageEntity#146]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.persister.entity.AbstractEntityPersister  - Fetching entity: [com.emailarchive.entity.MessageEntity#146]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.loader.Loader  - loading entity: [com.emailarchive.entity.MessageEntity#146]
2007-06-10 14:46:02,540 [btpool0-6] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2007-06-10 14:46:02,556 [btpool0-6] DEBUG org.hibernate.SQL  -


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 11, 2007 7:24 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
please use the standard template when asking for help.
What are the versions you use?

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 12, 2007 9:22 am 
Beginner
Beginner

Joined: Tue Nov 29, 2005 4:42 pm
Posts: 49
Location: Atlanta, GA
Hibernate version:

Hibernate version: 3.2.3.ga
Hibernate annotations: 3.3.0.GA
Hibernate Search: 3.0.0.Beta3


Mapping documents:

Code:
@Entity
@Table(schema ="APP", name = "MESSAGES")
@Indexed(index = "APP.MESSAGES")
@Proxy( lazy = false )
public class MessageEntity {

    @ManyToOne( cascade = CascadeType.PERSIST, fetch = FetchType.LAZY )
    @JoinColumn( name="BINARY_DATA_ID" )
    @JSON( include = false )
    public BinaryData getMessage() {
        return message;
    }

    public void setMessage(BinaryData message) {
        this.message = message;
    }
}


Code:
@Entity
@Table( schema ="APP", name = "BINARYDATA" )
@Proxy( lazy = false )
public class BinaryData {
    private Integer id;
    private byte[] data = null;

    @Basic
    @Column( name = "data", columnDefinition = "BLOB" )
    public Blob getBlob() {
        Blob blob = null;
        try {
            blob = data != null ? Hibernate.createBlob( toStream() ) : null;
        } catch (IOException ignore) {
        }
        return blob;
    }

    public void setBlob(Blob blob) throws SQLException {
        if( blob != null ) {
            this.data = blob.getBytes( 1L, (int)blob.length() );
        } else {
            this.data = null;
        }
    }
}


Code between sessionFactory.openSession() and session.close():

Code:
org.hibernate.Query query = manager.getSession().createQuery("from MessageEntity where id = ?");
query.setInteger( 0, id );
return (MessageEntity)query.uniqueResult();


So this is when I don't want to load the binary data objects.

Name and version of the database you are using:

Apache Derby 10.2

The generated SQL (show_sql=true):

See the above message

Debug level Hibernate log excerpt:

See above message


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 13, 2007 3:09 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Ah you set @Proxy( lazy = false )
never do that, I shouldn't have allowed this flag :)

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 13, 2007 10:20 pm 
Beginner
Beginner

Joined: Tue Nov 29, 2005 4:42 pm
Posts: 49
Location: Atlanta, GA
Yep that was the problem. But....

Well there are a lot of problems in the way in which hibernate implements proxies of many to one. Primarily if you are signing your java code. If you sign your code and do NOT set @Proxy( lazy = false ) then your class won't load. Primarily because the dynamic subclass created by hibernate is inside the same package as the subclass, but it's signer information is different. Java security procedures do not like classes that belong to the same package as a signed class that aren't signed. This is your only choice to work around the issue, but really is this a work around if these are the consequences?!

Can you give a good explanation as to why hibernate eagerly loads many to ones that have @Proxy(lazy=false)? I think I know why, but I just want to know for sure.

I'm also having problems turning off lazy = false and I'm getting this exception:

Code:
org.hibernate.HibernateException: CGLIB Enhancement failed: com.emailarchive.entity.BinaryData
   at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxy(CGLIBLazyInitializer.java:96)
   at org.hibernate.proxy.pojo.cglib.CGLIBProxyFactory.getProxy(CGLIBProxyFactory.java:49)
   at org.hibernate.tuple.entity.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:379)
   at org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:3453)
   at org.hibernate.event.def.DefaultLoadEventListener.createProxyIfNecessary(DefaultLoadEventListener.java:257)
   at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:191)
   at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)
   at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
   at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:846)
   at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:557)
   at org.hibernate.type.EntityType.resolve(EntityType.java:379)
   at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:116)
   at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:854)
   at org.hibernate.loader.Loader.doQuery(Loader.java:729)
   at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
   at org.hibernate.loader.Loader.doList(Loader.java:2220)
   at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
   at org.hibernate.loader.Loader.list(Loader.java:2099)
   at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:94)
   at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1569)
   at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
   at org.hibernate.search.engine.QueryLoader.load(QueryLoader.java:65)
   at org.hibernate.search.query.FullTextQueryImpl.list(FullTextQueryImpl.java:224)
   at com.emailarchive.web.model.MessageDao.search(MessageDao.java:32)
   at com.emailarchive.web.controller.MailSearchActionBean.search(MailSearchActionBean.java:37)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at net.sourceforge.stripes.controller.DispatcherHelper$6.intercept(DispatcherHelper.java:445)
   at net.sourceforge.stripes.controller.ExecutionContext.proceed(ExecutionContext.java:157)
   at net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor.intercept(BeforeAfterMethodInterceptor.java:107)
   at net.sourceforge.stripes.controller.ExecutionContext.proceed(ExecutionContext.java:154)
   at net.sourceforge.stripes.controller.ExecutionContext.wrap(ExecutionContext.java:73)
   at net.sourceforge.stripes.controller.DispatcherHelper.invokeEventHandler(DispatcherHelper.java:443)
   at net.sourceforge.stripes.controller.DispatcherServlet.invokeEventHandler(DispatcherServlet.java:241)
   at net.sourceforge.stripes.controller.DispatcherServlet.doPost(DispatcherServlet.java:154)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
   at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:491)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1074)
   at net.sourceforge.stripes.controller.StripesFilter.doFilter(StripesFilter.java:181)
   at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1065)
   at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:365)
   at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:185)
   at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
   at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:689)
   at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:391)
   at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:146)
   at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
   at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
   at org.mortbay.jetty.Server.handle(Server.java:285)
   at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:457)
   at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:765)
   at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:627)
   at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:209)
   at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:357)
   at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:329)
   at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:475)
Caused by: java.lang.InstantiationException: com.emailarchive.entity.BinaryData$$EnhancerByCGLIB$$45d5cbd
   at java.lang.Class.newInstance0(Class.java:340)
   at java.lang.Class.newInstance(Class.java:308)
   at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxyInstance(CGLIBLazyInitializer.java:107)
   at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxy(CGLIBLazyInitializer.java:93)
   ... 58 more


This was caused by a private no-arg constructor. If I switch it to protected it works. But, the documentation doesn't tell you to be careful. In fact I thought it said it was ok to have private no-arg constructors.

There are a lot of little things that matter that could have been highlighted bettter in the documenation regarding proxies.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 14, 2007 12:04 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
There is a doc about signed code and CGLIB in their website.
The protected constructor is described in the reference documentation.

Hibernate uses a proxy class to give you back an object reference even if the object is not loaded. No proxy, no lazyness

_________________
Emmanuel


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.