Lazy_fetching_Hibernate_property

Quick Profile

Alex Ooi Profile Picture
Hometown: Melbourne, Australia
Specializations: Java, Ruby on Rails
University: Software Engineering & Economics, Melbourne University
High School: VCE, Melbourne High School
Links:
 

Popular Articles

Wednesday, April 06, 2011

Today I needed to do a small performance enhancement on an application using Hibernate annotations. The optimization was to ensure that a @Lob property on a Hibernate entity was lazy loaded. By default Hibernate will allow you to lazy load associations, but any lazy loading of an entities properties is not enabled by default. This is how I went about achieving the small optimization...

I had an entity class called "UploadedData", and on it was a property called "data". It looked like below:


@Entity
@Table(name = "uploaded_datas")
public class UploadedData
{
    ....

    @Column(name = "name")
    private String name;

    @Lob
    @Column(name = "data")
    @Basic(fetch = FetchType.LAZY)
    private byte[] data;

    ....
}

Note that the "data" attribute is annotated to be lazily fetched. This was to avoid having to load large chunks of binary data into memory when it wasn't necessarily required to be made available to the client (often I only ever needed to get the "name" of the entity).

However, the SQL generated for selecting from the "uploaded_datas" table naturally still contained the binary data column in the list of selected columns when selecting entities from the table. It looked like this (notice the inclusion of the "data" column in the list of selected columns):


    select
        uploadedda0_.id as id11_1_,
        uploadedda0_.uploaded_data_category_id as uploaded7_11_1_,
        uploadedda0_.content_type as content2_11_1_,
        uploadedda0_.downloadable as download3_11_1_,
        uploadedda0_.filename as filename11_1_,
        uploadedda0_.name as name11_1_,
        uploadedda0_.data as data11_1_,     -- <========== eagerly loaded data
        uploadedda1_.id as id10_0_,
        uploadedda1_.name as name10_0_ 
    from
        uploaded_datas uploadedda0_ 
    left outer join
        uploaded_datas_categories uploadedda1_ 
            on uploadedda0_.uploaded_data_category_id=uploadedda1_.id

In order to enable lazy fetching on this attribute I needed to do some byte code instrumentation...

A useful ant task

So, I'm naturally using Maven. I included the following dependencies into the relevant module:

        
            org.hibernate
            hibernate-core
            3.3.1.GA
            runtime
        
        
            javassist
            javassist
            3.8.0.GA
            runtime
        
        
            org.apache.ant
            ant
            1.7.1
        

This provided the hibernate classes required to instrument entities for lazy fetching of attributes. And the ant classes needed to run ant. Next, I hooked in a call to the relevant Ant plugin that the hibernate dudes made available for instrumenting classes:

    
        

.....

            
                maven-antrun-plugin
                
                    
                        process-classes
                        
                            run
                        
                    
                
                
                    
                        
                            
                                
                                
                            
                        
                        
                            
                                
                            
                        
                    
                
            

.....

        
    

Notice that I specified the name of the only class (for the time being) that I want instrumented. Pretty easy. The ant task would be run during the "process-classes" phase of the maven lifecycle, and perform whatever magic it needs to enable the lazy-fetching annotation to work correctly. And thats it! All I needed to do after that was re-compile using maven (mvn clean install), and this automatically triggered the byte code instrumentation via the ant task. Brilliant! Once again a prime example of a build system working via configuration over implementation (where maven == "configuration" and ant == "implementation")...

The Result

I had Hibernates SQL output turned on throughout this whole process. The final result of loading a page with alot of uploaded data entities was as follows:


     -- no longer includes the data column in the list of selected columns!!
    select  
        uploadedda0_.id as id11_1_,
        uploadedda0_.uploaded_data_category_id as uploaded7_11_1_,
        uploadedda0_.content_type as content2_11_1_,
        uploadedda0_.downloadable as download3_11_1_,
        uploadedda0_.filename as filename11_1_,
        uploadedda0_.name as name11_1_,
        uploadedda1_.id as id10_0_,
        uploadedda1_.name as name10_0_ 
    from
        uploaded_datas uploadedda0_ 
    left outer join
        uploaded_datas_categories uploadedda1_ 
            on uploadedda0_.uploaded_data_category_id=uploadedda1_.id


    -- a NEW SECOND, EXPLICIT select statement will load data only when required
    select    
            uploadedda_.data as uploaded6_11_ 
        from
            uploaded_datas uploadedda_ 
        where
            uploadedda_.id=?

And thats it! The "data" column is not included in the first select (which returned all rows from the uploaded_datas table). However, when the "data" was required from one of the UploadedData entities then Hibernate generated the second select, returning the huge BLOB for that entity specifically. Brilliant ...

Comments ...

Holy Guacamole! Nobody has commented on this post yet! Why don't you make a name for yourself and be the first to do so ... Any comment whatsoever, as long as it is non-defamatory, will be welcome!

Add a Comment

*
*
You must answer the following simple maths question before your comment will be accepted.
*