-->
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.  [ 1 post ] 
Author Message
 Post subject: Making Blobs work with EJB3 Entity Manager and PostgreSQL
PostPosted: Thu Aug 17, 2006 10:37 am 
Newbie

Joined: Wed Jul 26, 2006 11:06 am
Posts: 11
I've seen a lot of posts regarding storing large binary files or large text files in the database and making them lazily fetched by hibernate. These are good questions because it's not intuitively obvious, especially new users of Hibernate.

I found myself in this exact position so I would like to share my experience and what worked for me. I'm not an expert so take this information for what it is - my experience and observations.

Keep in mind my environment as well.
JBoss AS 4.0.4.GA
Seam 1.0.1.GA
Hibernate 3.1
PostgreSQL 8.1

This post is in two parts. The parts are related but describe different issues.

Part 1
The first issues lies with the databases. Their documentation tells you to use some form of array (and this leads you astray). In postgresql they encourage the use of byte[] for binary large objects which Hibernate then correctly maps to a postgresql bytea[].

So this is what we did. We created a classed that contained a byte[] to store our images in. Looked like this.
Code:
@Entity
@Table(name="elements")
public class Element {
  private byte[] image;

  public getImage() {
    return image;
  }
}


This worked just fine, but the image property was not lazily loaded which is what you want most of the time. So we tried this...

Code:
@Entity
@Table(name="elements")
public class Element {
  private byte[] image;

  @Basic(fetch=FetchType.LAZY)
  public getImage() {
    return image;
  }
}


This did not work. Performance was terrible because all the Element classes and their images were being eagerly fetched. The next step was to move the storage to an actual blob to see if that helped. So we annotated the property like so. Note the @Lob annotation.

Code:
@Entity
@Table(name="elements")
public class Element {
  private byte[] image;

  @Lob @Basic(fetch=FetchType.LAZY)
  public getImage() {
    return image;
  }
}


Hibernate produced perfect SQL for creating the table and we thought we had figured it out. To no avail the images were still eagerly fetched. Plus a new bug was introduced with the @Lob annotation (described in Part2). Some tough searching on the Hibernate board led to this post which was a big help. This is the important part of the post
Quote:
java.sql.Lob is lazy loaded
byte[] is not lazy loaded

to lazy load an array of byte you need to enhance you class (build time enhancement, check the tools section of the hibernate reference doc) and use @Basic(LAZY)

Full Post: http://forum.hibernate.org/viewtopic.php?t=962140

With this new found know we changed byte[] to Blob like so...

Code:
@Entity
@Table(name="elements")
public class Element {
  private Blob image;

  @Lob @Basic(fetch=FetchType.LAZY)
  public getImage() {
    return image;
  }
}


This worked perfectly and excatly how we wanted it to work. Perfance was great. However, we still had the problem created by switching to a Blob. The solution is incomplete at this point.

Part 2
Our application is web based and at its most basic level it recieves uploaded financial document images, stores them in a database and then lets the user manipute metadata regarding the document. Nothing to terribly complicated.

The users do have the option to revisit web pages to review or continue editing the meta data. The new problem (using Blob) popped up on the second access of the images. For example: the user would load the image page and change some metadata, leave the page, then come back to it to change more data. When the page was loaded the second time the following exception occured
Code:
ERROR: invalid large-object descriptor: 0
SQLState: 42704


To make a long story short, we tracked this down to a problem using EXTENDED context management. Our original code looked like this...
Code:
@PersistenceContext(unitName = "DC", type=PersistenceContextType.EXTENDED)
  private EntityManager em;


When we changed it to use the default transaction scheme
Code:
@PersistenceContext(unitName = "DC")
  private EntityManager em;

everything worked fine. See this post http://forum.hibernate.org/viewtopic.php?t=963507 for more information.

So the moral of the story is this...

To use store large binary data and have it lazily fetched you need to do the following:

1. Use java.sql.Blob
2. Tell Hibernate to use lazy fetching
3. Keep your PersistenceContext transactional and not extended

Hope this helps.

Thanks.
Eric Ray


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

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.