Sunday, 17 August 2008

How to store and retrieve BLOB object using hibernate

As my first Blog entry, I just wanted to share one problem I faced yesterday while doing my personal project.


Problem :

How to store and retrieve BLOB object using hibernate. My requirement was to upload and download .doc files.

Solution:

1) Declare a column resume having MEDIUMBLOB as datatype.

2) Inside hibernate business Object declare the resume field with type byte[] and have the methods to convert the BLOB object from database into byte array.



public class UserDetails extends GenericBO{

private byte[] resume;

public byte[] getResume() {
return resume;
}
public void setResume(byte[] resume) {
this.resume = resume;
}

/** Don't invoke this. Used by Hibernate only. */
public void setResumeBlob(Blob resume) {
this.resume = this.toByteArray(resume);
}

/** Don't invoke this. Used by Hibernate only. */
public Blob getResumeBlob() {
return Hibernate.createBlob(this.resume);
}

private byte[] toByteArray(Blob fromBlob) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
return toByteArrayImpl(fromBlob, baos);
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException ex) { } } } }

private byte[] toByteArrayImpl(Blob fromBlob, ByteArrayOutputStream baos)
throws SQLException, IOException {
byte[] buf = new byte[4000];
InputStream is = fromBlob.getBinaryStream();
try { for (;;) {
int dataSize = is.read(buf);
if (dataSize == -1) break;
baos.write(buf, 0, dataSize); } } finally { if (is != null) {
try { is.close(); } catch (IOException ex) { } } }
return baos.toByteArray(); }

}

public abstract class GenericBO implements Serializable,Auditable {

private String lastUpdatedBy;

public String getLastUpdatedBy() {
return lastUpdatedBy;
}

public void setLastUpdatedBy(String lastUpdatedBy) {
this.lastUpdatedBy = lastUpdatedBy;
}

public Serializable save() {
return HibernateUtil.getInstance().currentSession().save(this);
}

public void delete() {
HibernateUtil.getInstance().currentSession().delete(this);
}
}




3. Include property resume in hibernate mapping file

<property name="resumeBlob" type="blob" column="resume" />


4. If you are using apache behieve as your Presentation layer framework, the data type of the resume field must be of type FormFile like below


public class UserDetailsTO implements Serializable{

private FormFile file;

// this is used only when retriving from database.
private byte[] resume;

public byte[] getResume() {
return resume;
}
public void setResume(byte[] resume) {
this.resume = resume;
}
public FormFile getFile() {
return file;
}
public void setFile(FormFile file) {
this.file = file;
}

}




5. To insert the resume in business process layer , first you have to read bytes from file using Input Stream.


public Long postResume(UserDetailsTO userDetailsTO){
Long id = new Long(0);
try {
Session session =HibernateUtil.getInstance().currentSession();
Transaction transaction= session.beginTransaction();

UserDetails resumeDetails = new UserDetails();

//reading bytes from InputStream
InputStream inputStream=userDetailsTO.getFile().getInputStream();
byte[] b = new byte[inputStream.available()];
inputStream.read(b);

resumeDetails.setResume(b);

id = (Long)resumeDetails.save();
transaction.commit();


} catch (Exception e) {
logger.debug(e.getMessage(),e);
throw new RuntimeException(e);
}
return id;
}





6. How to download the file


public class ShowResume extends HttpServlet {

javax.servlet.ServletOutputStream servletoutputstream = null;

public void service(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)
throws ServletException, IOException
{
HttpSession session=httpservletrequest.getSession(false);

UserDetailsTO resumeDetailsTO = null;


resumeDetailsTO=(UserDetailsTO)session.getAttribute(PresentationConstants.RESUME_DETAILS);



byte b[]=resumeDetailsTO.getResume();

try {
httpservletresponse.setContentType("application/ms-word");
httpservletresponse.setHeader("Content-Disposition", "inline;filename=report.doc");
servletoutputstream = httpservletresponse.getOutputStream();
servletoutputstream.write(b, 0, b.length);
servletoutputstream.close();
servletoutputstream = null;
b = null;
}catch(Exception ex) {
ex.printStackTrace();
}
}
}




Hope this code helps for those who are having the same requirement...

31 comments:

sneha prashant said...

hi sneha,

Nice blog.Good thought to open blog finally!!

Welcome to blog world...

thanks
prashant
http://www.prashantjalasutram.blogspot.com/

Vasu said...

Hi,
SnehaPrasanth,

Nice one. But we do not have any idea on this.

Vasu

pramod said...

Hi Sneha,
Good Initiation from your side....Keep it up.But I cannot comment on Technivcal details as i am not aware of that...
Take Care

Bernard said...

One problem with his approach is that the entire blob is loaded into memory due to the use of the byte[]. Consider what would happen if this was used in a web based application with hundreds of users all reading and writing their blob fields simultaneously?

Hibernate provides an implementation of the java.sql.Blob interface which you can use instead of a byte[]. You can read and write the blob data by using streams which is more efficient. See the Hibernate.createBlob() method.

sneha prashant said...

hi bernard,

Thanks for your comments.Infact we are using hibernate.createblob() method.

Reason why we are supporting byte() also is i was told that there was some issue with hibernate when using blob and we need to support in both ways.

Let me know if you have any other thoughts.

Thanks
Sneha

sneha prashant said...

Hi Pramod and Vasu,

Thanks for your encouragement.

naren said...

hai sneha..
its very gud idea to create a blog to interact with people, regarding articles i cant say anything abt the articles(no idea..). gud job done,Keep it up...

Thanks
Naren

sneha prashant said...

Thanks Naren. I will surely try to post some non technical article also.

Mahesh said...

I tried your solution for Hibernate3 and using oracle 10 driver. It did not work. Was just not save to retrieve the BLOB and hence consequently retrieve it. I had a BLOB colum instead of MEDIUMBLOB.. don't think that would have made a difference..

muralikrishna said...

Hai Sneha,

I am very happy to see ur blog. Very good. Keep it up. On technicle I cannot make any comment. The otherone is very good.

..Muralikrishna

Mahesh said...

Hi Sneha,

The solution works very well. Appologies for my previous post and bad grammar :) It was a mistake in my code that unfortunately led me to believe that your solution does not work. So thanks for the solutions...

Regards,
Mahesh

Prashant Jalasutram said...

Mahesh,

Thanks for your comments.Good that it worked.

Thanks
Sneha

Anish said...

hi sneha
I just tried your program but i am getting some error

1188 [main] WARN util.JDBCExceptionReporter - SQL Error: 17090, SQLState: null
1188 [main] ERROR util.JDBCExceptionReporter - operation not allowed: streams type cannot be used in batching
1203 [main] ERROR impl.SessionImpl - Could not synchronize database state with session

I am using hibernate 2 and oracle 10. Also I m not getting file from form ,directly taking from memmory
can u tell what is the reaseon for this erro

And downloding part what is

PresentationConstants.RESUME_DETAILS

sneha prashant said...

Hi Anish,

Sorry to say but,I am unable to get your problem. If possible can you please send me that code bit.

And I also want to know whether you have opened hibernate session before saving the state or not.

shilpa said...

snehuuuuuuuuuuuuuuuuuuuuuu its too good,but i dont have any knowledge regarding this coding uphhhhhhh.Good encouragement from prasanth,u may not even know where ur husbands push towards edu' will place u in future.All d best

Shilpa.

Moiaz said...

Hi SNEHA

I have a requirement and i am damn sure you can help me with it.
I have to store images in my database. Once its done, i have to display it in a jsp page.
I tried your code but i m not able to find HibernateUtil class and Auditable class. I am using Hibernate3.2 jar files and jdk 1.4,still m not able to find these two classes. I searched for them in findjar.com but those are pointing to different classes of this name. Can you plz upload your collection of classes.

Thanks and regards
Moiaz

sneha prashant said...

Hi Moiaz,
Those are my utility classes. If you think I can help you please send me your mailId so that I can mail you those files.

Ulf Reiman said...

Hi sneha prashant!

I was reading your blog, and found that you have solve the problem, i have now, to upload and download .doc files with hibernate, you say that you have some utility classes HibernateUtil class and Auditable class. Is it possilby you could mail these classes to me at ulf.reiman@gmail.com

/Ulf R

nan said...

Hi sneha,
Do we really need
Auditable class to upload and download the blob object.
If its mandatory could you please send me those file to my mail id
it is nandhamyr@gmail.com
Thanks.
Regards
nandha.

sneha prashant said...

Hi Nan,

No not really. Auditable is just an interface to add some other utility, but I am sure there is no need of Auditable Interface to upload/download BLOB object in Hibernate.

Thanks,
Sneha.

nan said...

Hi sneha,
could you please send the workspace to my mail.
nandhamyr@gmail.com

I am getting exception while map byte[] to blob. i am not sure about hbm.xml file also.
kindly send me as soon as possible
will help me to finish crucial dead line.

thanks
nandha.

Moiaz said...

sorry for replying late sneha...
can u please send me your sample code of 'how to store and retrieve BLOB object using hibernate'.
I really appreciate your help
my id-
moiaz.jiwani@gmail.com

thanks

venkat said...

Nice post on Blob reading and writing blob data. It is very informative and helpful. Please post more and more.

Siddharth Jain said...

Hy,
I am doing the same thing using Hibernate But when I call HQL save (session.save),I got an error
Caused by: java.sql.SQLException: operation not allowed: streams type cannot be used in batching

can u pls solve my problem

suresh said...

hi sneha

your example is good.but I'm unable to understand your code.my requirement is storing and retrieving images into database(mysql) using hibernate. can you send the code to my mail id plz
sureshmonopolyinjava@gmail.com

Rajiv said...

Hi Sneha,

My name is Rajiv. And after reading your blog on "Upload/Download a .doc file using hibernate" I became curious to implement a sample program to understand the intricacies of it. If you don't mind can you please send me the sample code to mail2rajivvenugopal@yahoo.co.in to try it out in my development platform. This could be helpful in most of the enterprise applications. That's why want to be one step ahead.

Thank you
Rajiv

Vipul said...

Hi sneha
I tied your code to store my image file as BLOB but its giving me error while uploading greater than 4000 bytes in size

Deena K said...

Thanks sneha, this blog helped me to resolve my issue with storing BLOB using hibernate.

good job, continue your service...

patil said...

Hi Sneha,

Nice blog,I am facing problem while storing the files, could you please send the workspace to the following id, pushpa.patil@gmail.com.

Thanks
Pushpa

Anand said...

Thanks !!

This is exactly what I wanted

Srini.T said...

Very useful post .... thx a lot