Java大對象類型的Hibernate映射

Java 中, java.lang.String 可用於表示長字符串(長度超過 255 ),字節數組 byte[] 能夠用於存放圖片戶或文件二進制數據。此外,在 JDBC API 中還提供了 java.sql.CLOB java.sql.BLOB 類型,他們分別表示標準 SQL 中的 CLOB (字符大對象)和 BLOB (二進制大對象)類型。表 2.4 列出了 Java 大對象, Hibernate 映射類型以及標準 SQL 的對應關係。
2.4
 
 
 
 
映射類型
Java 類型
標準 SQL 類型
binary
byte[]
VARBINARY( 或者 BLOB)
text
java.lang.String
CLOB
serilizable
實現 java.io.Serializable 的任何一個 Java
VARBINARY( 或者 BLOB)
clob
java.sql.CLOB
CLOB
blob
java.sql.BLOB
BLOB
注意:不容許用表 2.4 中列出的數據類型來定義持久化類的 OID
2 )、 BLOB,CLOB 數據的處理(以 Oracle 數據庫爲例):
  假設咱們有以下表
 
T_User 
id     number   <pk>
name varchar2(50)
age    number
image    BLOB
resume   CLOB          
  對應的映射文件以下:
<hibernate-mapping>
 <class name=」com.neusoft.hibernate.db.entity.TUser」 table=」T_User」>
<id name=」id」 column=」id」 type=」java.lang.Integer」>
 <generator class=」native」/>
</id>
<property name=」name」 type=」java.lang.String」 column=」name」/>
<property name=」age」 type=」java.lang.Integer」 column=」age」/>
<property name=」image」 type=」java.sql.Blob」 column=」image」/>
<property name=」resume」 type=」java.sql.Clob」 column=」resume」/>
 </class>
</hibernate-mapping>
實體類以下:
public class Tuser implements Serializable{
 private Integer id;
 private String name;
 private Integer age;
 private Blob image;
 private Clob resume;
 …getter/setter…..
}
BLOB CLOB 這種大對象通常都是採用流機制做爲數據讀取方式,因此這種讀取方式在 Oracle 這種自視爲數據庫中貴族的數據庫中對這種操做就會有諸多的限制,有時候會叫人以爲不太友好(這是典型的店大欺客)
限制一: Oracle JDBC 不容許流操做以批量方式執行,若是發生這種錯誤通常會拋出
ERROR JDBCExceptionReport:streams type cannot be used in batching. 出現這種狀況通常都須要將 hibernate.cfg.xml 中的 hibernate.jdbc.batch_size 設定爲 0 便可消除,可是這就會影響其餘的更新,插入,刪除操做的性能,所以必須在一個數據庫事務中對 Clob,Blob 進行操做,也只有在一個數據庫事務中 Clob,Blob 對象纔會有效。
限制二: Oalce Blob/Clob 具備獨特的訪問方式,這種類型字段擁有一個遊標 (cursor) JDBC 必須經過遊標對 Blob/Clob 進行操做,在 Blob/Clob 建立以前我門沒法得到其遊標句炳,這就意味着必須首先建立一個空 Blob/Clob 字段,在叢空 Blob/Clob 獲取遊標,而後寫入咱們指望的數據。
 
首先看一下采用傳統 JDBC 進行操做的代碼:
//…. 獲取 Connection 鏈接
conn.setAtuoCommit(false);
// 插入 Blob/Clob 空值字段
PrepareStatement prestmt=conn.prepareStatement(「insert into T_USER(name,age,id,image,resume) values(?,?,?,?,?)」);
prestmt.setString(1,」zx」);
prestmt.setInt(2,26);
prestmt.setInt(3,5);
// 經過 oracle.sql.BLOB/CLOB.empty_lob() 方法構造空 Blob/Clob 對象
prestmt.setBlob(4,oracle.sql.BLOB.empty_lob());
prestmt.setClob(5,oracle.sql.CLOB.empty_lob());
prestmt.executeUpdate();
prestmt.close();
// 再次從數據庫中得到 Blob/Clob 句炳
prestmt=conn.prepareStatement(「select image,resume from T_USER where id=? for update 」);
prestmt.setInt(1,5);
ResultSet rset=prestmt.executeQuery();
rset.next();
oracle.sql.BLOB imgBlob=(oracle.sql.BLOB)rset.getBlob();
oracle.sql.CLOB resClob=(oracle.sql.CLOB)rset.getClob();
// 將二進制數據寫入 Blob
FlieInputStream fin=new FileInputStream(「c://image.jpg」);
OutputStream out=imgBlob.getBinaryOutputStream();
byte[] buf=new byte[fin.available()];
int len;
while((len=fin.read(buf))!=-1){
 out.write(buf,0,len);
}
fin.close();
out.close();
// 將字符串寫入 Clob
resClob.putString(1,」This is my clob」);
// 將更新寫回數據庫
prestmt=conn.prepareStatement(「update T_USER set image=?,resume=? where id=? 」);
prestmt.setBlob(1,imgBlob);
prestmt.setClob(2,resClob);
prestmt.setInt(3,5);
prestmt.executeUpdate();
prestmt.close();
conn.commit();
conn.close();
 
 
以上是傳統的採用 JDBC 方式處理,注意他將鏈接的自動提交屬性設置爲 false 而後將全部的操做併入一個事務中,而後進行提交,這是處理 Oracle Blob/Clob 字段的通常機制,因此 Hibernate 的處理就應該模仿 JDBC 的處理方式,由於從某種角度來說 Hibernate 是對 JDBC 的封裝由於它的底層訪問機制仍然是基於 JDBC 的。
 
Hibernate 的處理:
TUser user=new TUser();
user.setAge(new Integer(26));
user.setName(「zx」);
// 建立空 Blob/Clob 對象
user.setImage(Hibernate.createBlob(new byte[1]));
user.setResume(Hibernate.createClob(「 「));// 注意這裏的參數是一個空格
Transaction tx=session.beginTransaction();
session.save(user);
// 調用 flush 方法,強制 Hibernate 當即執行 insert sql
session.flush();
// 經過 refresh 方法,強制 Hibernate 執行 select for update
session.refresh(user,LockMode.UPGRADE);
// Blob 寫入實際內容
oracle.sql.BLOB blob=(oracle.sql.BLOB)user.getImger();
OutputStream out=blob.getBinaryOutputStream();
FileInputStream fin=new FileInputStream(「c://image.jpg」);
byte[] buf=new byte[fin.available()];
int len;
while((len=fin.read())!=-1){
 out.write(buf,0,len);
}
fin.close();
out.close();
// Clob 中寫入數據
oracle.sql.CLOB clob=user.getResume();
java.io.Writer writer=clob.getCharacterOutputStream();
writer.write(「This is my resume!」);
writer.close();
session.saveOrUpdate(user);
session.commit();
tx.commit();
 
在實際應用中,對於 Clob 字段能夠簡單的將其映射爲 String 類型,不過在 Oracle Thin Driver Clob 字段支持上有欠缺,當 Clob 內容超過 4000 字節時將沒法讀取,而 Oracle OCI Driver( 須要在本地安裝客戶端組件 ) 則能夠完成大容量 Clob 字段操做。
 
對於上面的代碼相信做爲成熟的工程師來講都聞到一些 bad smell, 若是 Blob/Clob 字段廣泛存在的話,那麼咱們的持久層邏輯可能遍及這種複雜的邏輯,不過不要着急在我即將講解的客戶自定義類中咱們將會看到一個解決方案,經過自定義類型咱們能夠對數據類型的通用性進行抽象,對於 Blob/Clob 字段咱們能夠定義一種類型並以這種類型做爲 Blob/Clob 字段的映射類型。(好了等到下一篇再說吧!)
相關文章
相關標籤/搜索