hk2000c技术专栏

技术源于哲学,哲学来源于生活 关心生活,关注健康,关心他人

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  111 随笔 :: 1 文章 :: 28 评论 :: 0 Trackbacks

Hibernate 1.2.3 has built-in support for blobs. Hibernate natively maps blob columns to java.sql.Blob. However, it's sometimes useful to read the whole blob into memory and deal with it as a byte array.

One approach for doing this to create a new UserType as follows.

package mypackage;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.sql.Blob;
import cirrus.hibernate.Hibernate;
import cirrus.hibernate.HibernateException;
import cirrus.hibernate.UserType;
public class BinaryBlobType implements UserType
{
public int[] sqlTypes()
{
return new int[] { Types.BLOB };
}
public Class returnedClass()
{
return byte[].class;
}
public boolean equals(Object x, Object y)
{
return (x == y)
|| (x != null
&& y != null
&& java.util.Arrays.equals((byte[]) x, (byte[]) y));
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException
{
Blob blob = rs.getBlob(names[0]);
return blob.getBytes(1, (int) blob.length());
}
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException
{
st.setBlob(index, Hibernate.createBlob((byte[]) value));
}
public Object deepCopy(Object value)
{
if (value == null) return null;
byte[] bytes = (byte[]) value;
byte[] result = new byte[bytes.length];
System.arraycopy(bytes, 0, result, 0, bytes.length);
return result;
}
public boolean isMutable()
{
return true;
}
}

The BinaryBlobType will convert a blob into a byte array and back again.

Here's how to use it. First, define an entity that contains a byte[] property:

public class ImageValue
{
private long id;
private image byte[];
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public byte[] getImage() { return image; }
public void setImage(byte[] image) { this.image = image; }
}

Then map a blob column onto the byte[] property:

<class name="ImageValue" table="IMAGE_VALUE">
<id name="id/>
<property name="image" column="IMAGE" type="mypackage.BinaryBlobType"/>
</class>

Notes:

1) Blobs aren't cachable. By converting the blob into a byte array, you can now cache the entity.

2) This approach reads the whole blob into memory at once.

3) The above type is known to work for reading blobs out of the db. Other usage patterns might also work.

Comments (GK)

I changed isMutable() to return true, since an array is a mutable object.

The use of setBlob() will work on some drivers, but not all. I think its more portable to use setBytes() or even setBinaryStream().

comments (db)

db's comment above was right, setBlob() didn't work on Oracle, I used setBytes().

comments (Chad Woolley)

Below is a modified nullsafeset() that i needed to use to get it to work with tomcat 4.1.27 & oracle 8/9i - the normal calls don't work through the tomcat/dbcp connection pool wrapper objects... (this caused me great pain)

pls note that the setBytes() doesn't seem to work with oracle driver & hibernate

d.birch@eclipsegroup.com.au

public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException
{
if(st instanceof org.apache.commons.dbcp.DelegatingPreparedStatement &&
((org.apache.commons.dbcp.DelegatingPreparedStatement)st).getDelegate()
instanceof oracle.jdbc.OraclePreparedStatement)
{
oracle.sql.BLOB blob = oracle.sql.BLOB.createTemporary(
((org.apache.commons.dbcp.PoolableConnection)st.getConnection()).getDelegate(), false, oracle.sql.BLOB.DURATION_SESSION);
blob.open(BLOB.MODE_READWRITE);
OutputStream out = blob.getBinaryOutputStream();
try
{
out.write((byte[])value);
out.flush();
out.close();
}
catch(IOException e)
{
throw new SQLException("failed write to blob" + e.getMessage());
}
blob.close();
((oracle.jdbc.OraclePreparedStatement)((org.apache.commons.dbcp.DelegatingPreparedStatement)st).getDelegate()).setBLOB(index, blob);
}
else
{
st.setBlob(index, Hibernate.createBlob((byte[]) value));
}
}
//and.. note the null check, oracle drivers return a null blob...
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException
{
final Blob blob = rs.getBlob(names[0]);
return blob != null?blob.getBytes(1, (int)blob.length()):null;
}

/ comments Vanitha

I had to use the user type to save pdfs as oraBLOBs in oracle 91 database. nullsafeSet

needed a sligh modification , or else ther was a classcastexception. Used oracle Blob instead of Hibernate Blob type and it works.

 public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException
{
oracle.sql.BLOB t_blob = oracle.sql.BLOB.createTemporary(((org.jboss.resource.adapter.jdbc.WrappedConnection) st.getConnection()).getUnderlyingConnection(),
false, oracle.sql.BLOB.DURATION_SESSION);
OutputStream t_out = null;
t_blob.open(BLOB.MODE_READWRITE);
t_out = t_blob.getBinaryOutputStream();
try
{
t_out.write((byte[]) value);
t_out.flush();
t_out.close();
}
catch (IOException e)
{
throw new SQLException("failed write to blob" + e.getMessage());
}
t_blob.close();
st.setBlob(index, t_blob);
}

</code>

posted on 2007-11-16 17:46 hk2000c 阅读(1386) 评论(0)  编辑  收藏 所属分类: JMS

只有注册用户登录后才能发表评论。


网站导航: