Oracle Blob mapped to byte[] in Hibernate [ZT]
http://hansonchar.blogspot.com/2005/06/oracle-blob-mapped-to-byte-in.html
Oracle Blob mapped to byte[] in Hibernate
I refer to Oracle 9i and Hibernate 2.1 to 3.0.5.
As found in the Hibernate forum, there is a problem of mapping a byte[] JavaBean property to "binary" in the Hibernate mapping file. Basically the byte array can be written to Oracle, but what's read back from Oracle is always 86 bytes which is the Oracle Blob locator itself!
Here is one solution I've found to get around this problem, assuming, say, the byte[] property name is "image",
1. Keep an internal member field for the byte[] image, with the standard {get|set}Image methods;
2. Add a pair of {get|set}ImageBlob methods for getting and setting the Blob datatype, without the repsective Blob member field. This pair of methods are intended to be invoked only by Hibernate;
3. Change the property mapping from "image" to "imageBlob", and use "blob" instead of "binary" for the type in the Hibernate mapping file.
Now the blob can be written to and read back from Oracle as byte[] as expected.
Note, with this approach, you may need to use the Oracle 10.1.0.4+ JDBC thin driver regardless to get around a problem related to the blob size greater than 2K bytes (even if you are running the Oracle 9.2.0.x database). Apparently it's related to a bug in the 9.2.0.x JDBC driver.
Example:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.SQLException;
import org.hibernate.Hibernate;
public class Foo implements Serializable {
byte[] image;
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
/** Don't invoke this. Used by Hibernate only. */
public void setImageBlob(Blob imageBlob) {
this.image = this.toByteArray(imageBlob);
}
/** Don't invoke this. Used by Hibernate only. */
public Blob getImageBlob() {
return Hibernate.createBlob(this.image);
}
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();
}
}
Sample property mapping:
<property name="imageBlob" type="blob" column="IMAGE" />
Oracle Blob mapped to byte[] in Hibernate
I refer to Oracle 9i and Hibernate 2.1 to 3.0.5.
As found in the Hibernate forum, there is a problem of mapping a byte[] JavaBean property to "binary" in the Hibernate mapping file. Basically the byte array can be written to Oracle, but what's read back from Oracle is always 86 bytes which is the Oracle Blob locator itself!
Here is one solution I've found to get around this problem, assuming, say, the byte[] property name is "image",
1. Keep an internal member field for the byte[] image, with the standard {get|set}Image methods;
2. Add a pair of {get|set}ImageBlob methods for getting and setting the Blob datatype, without the repsective Blob member field. This pair of methods are intended to be invoked only by Hibernate;
3. Change the property mapping from "image" to "imageBlob", and use "blob" instead of "binary" for the type in the Hibernate mapping file.
Now the blob can be written to and read back from Oracle as byte[] as expected.
Note, with this approach, you may need to use the Oracle 10.1.0.4+ JDBC thin driver regardless to get around a problem related to the blob size greater than 2K bytes (even if you are running the Oracle 9.2.0.x database). Apparently it's related to a bug in the 9.2.0.x JDBC driver.
Example:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.SQLException;
import org.hibernate.Hibernate;
public class Foo implements Serializable {
byte[] image;
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
/** Don't invoke this. Used by Hibernate only. */
public void setImageBlob(Blob imageBlob) {
this.image = this.toByteArray(imageBlob);
}
/** Don't invoke this. Used by Hibernate only. */
public Blob getImageBlob() {
return Hibernate.createBlob(this.image);
}
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();
}
}
Sample property mapping:
<property name="imageBlob" type="blob" column="IMAGE" />
hofman
2005-10-21 00:53:44
评论:5
阅读:2427
引用:0
存在一个问题(接上三)
@2007-07-04 15:37:12 dudu
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.java:650)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:675)
at java.lang.Thread.run(Thread.java:595)
其中com.cmcc.mm7.vasp.dfadd.hibernate.Mm7recvDataModel是含有Blob型字段的POJO
utor.java:650)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:675)
at java.lang.Thread.run(Thread.java:595)
其中com.cmcc.mm7.vasp.dfadd.hibernate.Mm7recvDataModel是含有Blob型字段的POJO
存在一个问题(接上二)
@2007-07-04 15:34:59 dudu
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutio
ns(AbstractFlushingEventListener.java:297)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlus
hEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at com.cmcc.mm7.vasp.dfadd.hibernate.Mm7recvDataModelDAO.save(Mm7recvDat
aModelDAO.java:33)
at com.cmcc.mm7.vasp.dfadd.thread.DataRecvThread.ServiceConnect(DataRecv
Thread.java:189)
at com.cmcc.mm7.vasp.dfadd.thread.DataRecvThread.run(DataRecvThread.java
:640)
at java.util.concurrent.ThreadPoolExecutor$
ns(AbstractFlushingEventListener.java:297)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlus
hEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at com.cmcc.mm7.vasp.dfadd.hibernate.Mm7recvDataModelDAO.save(Mm7recvDat
aModelDAO.java:33)
at com.cmcc.mm7.vasp.dfadd.thread.DataRecvThread.ServiceConnect(DataRecv
Thread.java:189)
at com.cmcc.mm7.vasp.dfadd.thread.DataRecvThread.run(DataRecvThread.java
:640)
at java.util.concurrent.ThreadPoolExecutor$
存在一个问题(接上)
@2007-07-04 15:33:54 dudu
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert
(AbstractEntityPersister.java:2118)
at org.hibernate.persister.entity.AbstractEntityPersister.update(Abstrac
tEntityPersister.java:2374)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.ja
va:91)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutio
(AbstractEntityPersister.java:2118)
at org.hibernate.persister.entity.AbstractEntityPersister.update(Abstrac
tEntityPersister.java:2374)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.ja
va:91)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutio
存在一个问题
@2007-07-04 15:31:09 dudu
采用该方法的确可以实现图片文件存入数据库,但是当我插入大量数据时经常报如下错误:
2007-07-04 09:11:29,375 ERROR [org.hibernate.event.def.AbstractFlushingEventList
ener] - <Could not synchronize database state with session>
org.hibernate.exception.LockAcquisitionException: could not update: [com.cmcc.mm
7.vasp.dfadd.hibernate.Mm7recvDataModel#15964]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.j
ava:82)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelp
er.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.update(Abstrac
tEntityPersister.java:2222)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert
(AbstractEntityP
2007-07-04 09:11:29,375 ERROR [org.hibernate.event.def.AbstractFlushingEventList
ener] - <Could not synchronize database state with session>
org.hibernate.exception.LockAcquisitionException: could not update: [com.cmcc.mm
7.vasp.dfadd.hibernate.Mm7recvDataModel#15964]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.j
ava:82)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelp
er.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.update(Abstrac
tEntityPersister.java:2222)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert
(AbstractEntityP
非常棒
@2005-10-25 23:44:25 hofman
经过检验,确实是非常cool的方法。
