Hibernate、iBATIS 与 BLOB

2007-04-16   版权声明

我知道这篇文章阅读量很大,但是请要继续转载本文的同志注意一下,本文是我在 2005 年春节期间写的,春节是合家团圆的日子,所以在这个时候写点东西不容易,整整花了我将近 20 天的时间啊。请保留原文版权信息 OK?

----------------------------------------------------------------------------------------------------

在存储图片、可执行文件等二进制信息时(当然直接放在文件系统上也行), BLOB 数据就派上用场了。 本文无 太多 深度可言,能为大家在开发过程中提供参考足亦!

Hibernate 与 SQL Server BLOB

BLOB 数据在 SQL Server 数据库中主要由 IMAGE 类型体现,最大容量为 2GB 。其存储方式不同于普通的数据类型,对于普通类型的数据系统直接在用户定义的字段上存储数据值,而对于 IMAGE 类型数据,系统开辟新的存储页面来存放这些数据,表中 IMAGE 类型数据字段存放的仅是一个 16 字节的指针,该指针指向存放该条记录的 IMAGE 数据的页面。如果 你对 Hibernate 还不熟息,请看 这里

新建名为 “BLOB_TEST” 的表,字段分别是 INT 类型的 “ID” 和 IMAGE 类型的 “MYBLOB” 。从文件系统读取 “sample.jpg” 并转换成字节数组再放进 BlobTest 对象实例。 写入程序如下:

import java.io.*;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;

import bo.*;

public class Tester {

public void DoTest() {
  InputStream in = null;
  BlobTest blobTest = null;
  Configuration cfg = null;
  SessionFactory sessions = null;
  Session session = null;
  Transaction tx = null;
  try {
   //begin InputStream
   in = new FileInputStream("d:/sample.jpg");
   byte[] b = new byte[in.available()];
   in.read(b);
   in.close();

   //begin BlobTest
   blobTest = new BlobTest();
   blobTest.setMyblob(b);

   //begin Hibernate Session
   cfg = new Configuration().configure();
   sessions = cfg.buildSessionFactory();
   session = sessions.openSession();
   tx = session.beginTransaction();
   session.save(blobTest);
   tx.commit();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    session.close();
   } catch (Exception e1) {
    e1.printStackTrace();
   }
  }
}
}

 

取出 程序如下:

import java.io.*;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;

import bo.*;

public class Tester {

public void DoTest() {
  OutputStream out = null;
  BlobTest blobTest = null;
  Configuration cfg = null;
  SessionFactory sessions = null;
  Session session = null;
  try {
   //begin Hibernate Session
   cfg = new Configuration().configure();
   sessions = cfg.buildSessionFactory();
   session = sessions.openSession();

   //begin BlobTest
   blobTest = new BlobTest();
   blobTest = (BlobTest) session.load(BlobTest.class, new Integer(23));

   //begin OutputStream
   out = new FileOutputStream("d:/sample.jpg");
   out.write(blobTest.getMyblob());
   out.flush();
   out.close();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    session.close();
   } catch (Exception e1) {
    e1.printStackTrace();
   }
  }
}
}

  

Hibernate 与 MySQL BLOB

    MySQL 中的 BLOB 数据由四种类型体现,分别是 TINYBLOB 其容量为 256 字节、 BLOB 其容量为 64KB 、 MEDIUMBLOB 其容量为 16MB 、 LONGBLOB 其容量为 4GB 。

新建名为 “BLOB_TEST” 的表,字段分别是 INTEGER 类型的 “ID” 和 MEDIUMBLOB 类型的 “MYBLOB” 。从文件系统读取 “sample.jpg” 并转换成字节数组再放进 BlobTest 对象实例。 写入、 取出 程序和上面的 SQL Server 一样。

Hibernate 与 Oracle BLOB

    为了不使用 “for update” 锁住数据库,遂打算让 Oracle LONG RAW 类型保存大对象,最大容量 2GB 。经过测试后发现,直接写 JDBC 代码可以保存,但 Hibernate 只能保存 4K 大小内容,换成 Hibernate 3.0 beta3 也未能成功。偶然的机会在邮件列表上发现这是 JDBC Driver 的问题,换成 Oracle 10g 的驱动后问题解决。

新建名为 “BLOB_TEST” 的表,字段分别是 NUMBER 类型的 “ID” 和 LONG RAW 类型的 “MYBLOB” 。从文件系统读取 “sample.jpg” 并转换成字节数组再放进 BlobTest 对象实例。 写入、 取出 程序和 SQL Server 一样。

如果你一定要用 Oracle BLOB 类型,接着往下看:

    Hibernate 处理 Oracle BLOB 类型较特殊 , 从文件系统读取 “sample.jpg” 放进 BlobTest 对象实例的是 java.sql.Blob 类型,而不是字节数组。

import java.io.*;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import oracle.sql.*;

import bo.*;

public class Tester {

public void DoTest() {
  BLOB blob = null;
  InputStream in = null;
  OutputStream out = null;
  BlobTest blobTest = null;
  Configuration cfg = null;
  SessionFactory sessions = null;
  Session session = null;
  Transaction tx = null;
  try {
   //begin InputStream
   in = new FileInputStream("d:/sample.jpg");
   byte[] b = new byte[in.available()];
   in.read(b);
   in.close();
  
   //begin BlobTest
   blobTest = new BlobTest();
   blobTest.setMyblob(BLOB.empty_lob());
  
   //begin Hibernate Session
   cfg = new Configuration().configure();
   sessions = cfg.buildSessionFactory();
   session = sessions.openSession();
   tx = session.beginTransaction();
   session.save(blobTest);
   session.flush();
   session.refresh(blobTest, LockMode.UPGRADE);
   blob = (BLOB) blobTest.getMyblob();
   out = blob.getBinaryOutputStream();
   out.write(b);
   out.close();
   session.flush();
   tx.commit();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    session.close();
   } catch (Exception e1) {
    e1.printStackTrace();
   }
  }
}
}

  

取出 程序和其他两种数据库操作几乎一样。
 

iBATIS SQL Maps 与 SQL Server BLOB

    建表过程和 Hibernate 操作 SQL Server 一样,如果 你对 iBATIS SQL Maps 还不熟息,请看 这里

映射文件如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMap
    PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
    "
http://www.ibatis.com/dtd/sql-map-2.dtd ">

<sqlMap>

    <insert id="insertBlob" parameterClass="bo.BlobTest">
      <![CDATA[
        insert into blob_test (myblob) values (#myblob#)
      ]]>
      <selectKey resultClass="java.lang.Integer" keyProperty="id">
        <![CDATA[
          SELECT @@IDENTITY AS ID
        ]]>
      </selectKey>
    </insert>

    <resultMap id="get-blob-result" class="bo.BlobTest">
      <result property="id" column="id"/>
      <result property="myblob" column="myblob"/>
    </resultMap>

    <select id="getBlob" resultMap="get-blob-result" parameterClass="bo.BlobTest">
      <![CDATA[
        select * from blob_test where id=#id#
      ]]>
    </select>
       
</sqlMap>


写入程序如下:

import java.io.*;

import com.ibatis.sqlmap.client.*;
import com.ibatis.common.resources.*;

import bo.*;

public class Tester {

public void DoTest() {
  byte[] b=null;
  Reader reader = null;
  InputStream in = null;
  BlobTest blobTest = null;
  SqlMapClient sqlMap = null;
  String resource = "SqlMapConfig.xml";
  try {
   //begin InputStream
   in = new FileInputStream("d:/sample.jpg");
   b = new byte[in.available()];
   in.read(b);
   in.close();

   //begin BlobTest
   blobTest = new BlobTest();
   blobTest.setMyblob(b);

   //begin SqlMapClient
   reader = Resources.getResourceAsReader(resource);
   sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
   sqlMap.startTransaction();
   sqlMap.insert("insertBlob", blobTest);
   sqlMap.commitTransaction();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    sqlMap.endTransaction();
   } catch (Exception e1) {
    e1.printStackTrace();
   }
  }
}
}

 
取出程序如下:
 

import java.io.*;

import com.ibatis.sqlmap.client.*;
import com.ibatis.common.resources.*;

import bo.*;

public class Tester {

public void DoTest() {
  Reader reader = null;
  OutputStream out = null;
  BlobTest blobTest = null;
  SqlMapClient sqlMap = null;
  String resource = "SqlMapConfig.xml";
  try {
   //begin BlobTest
   blobTest = new BlobTest();
   blobTest.setId(new Integer(21));

   //begin SqlMapClient
   reader = Resources.getResourceAsReader(resource);
   sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
   blobTest = (BlobTest) sqlMap.queryForObject("getBlob", blobTest);

   //begin OutputStream
   out = new FileOutputStream("d:/sample.jpg");
   out.write(blobTest.getMyblob());
   out.close();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    sqlMap.endTransaction();
   } catch (Exception e1) {
    e1.printStackTrace();
   }
  }
}
}


iBATIS SQL Maps 与 MySQL BLOB

    这个主题很简单,需要注意映射文件 insert 元素主键生成方式, 写入、 取出 程序和上面的 SQL Server 一样 :

    <insert id="insertBlob" parameterClass="bo.BlobTest">
      <![CDATA[
        insert into blob_test (myblob) values (#myblob#)
      ]]>
      <selectKey resultClass="java.lang.Integer" keyProperty="id">
    <![CDATA[
          select last_insert_id();
    ]]>
      </selectKey>
  </insert>
 

iBATIS SQL Maps 与 Oracle BLOB

    使用 Oracle LONG RAW 类型, 注意映射文件 insert 元素主键生成方式, 写入、 取出 程序和上面的 SQL Server 一样 :

    <insert id="insertBlob" parameterClass="bo.BlobTest">
      <selectKey resultClass="int" keyProperty="id">
        <![CDATA[
          select hibernate_sequence.nextval from dual
        ]]>
      </selectKey>
      <![CDATA[
        insert into blob_test (id,myblob) values (#id#,#myblob#)
      ]]>
    </insert>

 

如果你一定要用 Oracle BLOB 类型,接着往下看:

在 iBATIS 2.0.9 以前,处理 Oracle BLOB 类型相当麻烦,要自己实现 TypeHandlerCallback 接口。 iBATIS 2.0.9 提供了 BlobTypeHandlerCallback 实现类,写入、 取出 程序和上面的 SQL Server 一样。只是映射文件 resultMap 元素 需要修改:

    <resultMap id="get-blob-result" class="bo.BlobTest">
      <result property="id" column="id"/>
      <result property="myblob" column="myblob"
              typeHandler="com.ibatis.sqlmap.engine.type.BlobTypeHandlerCallback"/>
    </resultMap>

应广大开发者的要求,我把BlobTest类源代码提交上来,当年用的是插件生成,一共有三个文件:

package old;

import java.io.Serializable;


/**
* This class has been automatically generated by Hibernate Synchronizer.
* For more information or documentation, visit The Hibernate Synchronizer page
* at
http://www.binamics.com/hibernatesync or contact Joe Hudson at joe@binamics.com.
*
* This is an object that contains data related to the BLOB_TEST table.
* Do not modify this class because it will be overwritten if the configuration file
* related to this class is modified.
*
* @hibernate.class
*  table="BLOB_TEST"
*/
public  abstract  class BaseBlobTest  implements Serializable {

   
public  static String PROP_MYBLOB =  " Myblob " ;
   
public  static String PROP_ID =  " Id " ;


   
private  int hashCode = Integer.MIN_VALUE;

   
// primary key
private java.lang.Integer _id;

   
// fields
private java.sql.Blob _myblob;


   
// constructors
public BaseBlobTest () {
        initialize();
    }

   
/**
     * Constructor for primary key
    
*/
   
public BaseBlobTest (java.lang.Integer _id) {
       
this .setId(_id);
        initialize();
    }

   
protected  void initialize () {}



   
/**
     * Return the unique identifier of this class
     * @hibernate.id
     *  generator-class="native"
     *  column="ID"
    
*/
   
public java.lang.Integer getId () {
       
return _id;
    }

   
/**
     * Set the unique identifier of this class
     *
@param _id the new ID
    
*/
   
public  void setId (java.lang.Integer _id) {
       
this ._id = _id;
       
this .hashCode = Integer.MIN_VALUE;
    }


   
/**
     * Return the value associated with the column: MYBLOB
    
*/
   
public java.sql.Blob getMyblob () {
       
return _myblob;
    }

   
/**
     * Set the value related to the column: MYBLOB
     *
@param _myblob the MYBLOB value
    
*/
   
public  void setMyblob (java.sql.Blob _myblob) {
       
this ._myblob = _myblob;
    }


   
public  boolean equals (Object obj) {
       
if ( null  == obj) return  false ;
       
if ( ! (obj instanceof old.BaseBlobTest)) return  false ;
       
else {
            old.BaseBlobTest mObj
= (old.BaseBlobTest) obj;
           
if ( null  ==  this .getId() ||  null  == mObj.getId()) return  false ;
           
else  return ( this .getId().equals(mObj.getId()));
        }
    }


   
public  int hashCode () {
       
if (Integer.MIN_VALUE ==  this .hashCode) {
           
if ( null  ==  this .getId()) return  super .hashCode();
           
else {
                String hashStr
=  this .getClass().getName() +  " : "  +  this .getId().hashCode();
               
this .hashCode = hashStr.hashCode();
            }
        }
       
return  this .hashCode;
    }


   
public String toString () {
       
return  super .toString();
    }

}


package bo.base;

import java.io.Serializable;


/**
* This class has been automatically generated by Hibernate Synchronizer.
* For more information or documentation, visit The Hibernate Synchronizer page
* at
http://www.binamics.com/hibernatesync or contact Joe Hudson at joe@binamics.com.
*
* This is an object that contains data related to the BLOB_TEST table.
* Do not modify this class because it will be overwritten if the configuration file
* related to this class is modified.
*
* @hibernate.class
*  table="BLOB_TEST"
*/
public  abstract  class BaseBlobTest  implements Serializable {

   
public  static String PROP_MYBLOB =  " Myblob " ;
   
public  static String PROP_ID =  " Id " ;


   
private  int hashCode = Integer.MIN_VALUE;

   
// primary key
private java.lang.Integer _id;

   
// fields
private  byte [] _myblob;


   
// constructors
public BaseBlobTest () {
        initialize();
    }

   
/**
     * Constructor for primary key
    
*/
   
public BaseBlobTest (java.lang.Integer _id) {
       
this .setId(_id);
        initialize();
    }

   
protected  void initialize () {}



   
/**
     * Return the unique identifier of this class
     * @hibernate.id
     *  generator-class="native"
     *  column="ID"
    
*/
   
public java.lang.Integer getId () {
       
return _id;
    }

   
/**
     * Set the unique identifier of this class
     *
@param _id the new ID
    
*/
   
public  void setId (java.lang.Integer _id) {
       
this ._id = _id;
       
this .hashCode = Integer.MIN_VALUE;
    }


   
/**
     * Return the value associated with the column: MYBLOB
    
*/
   
public  byte [] getMyblob () {
       
return _myblob;
    }

   
/**
     * Set the value related to the column: MYBLOB
     *
@param _myblob the MYBLOB value
    
*/
   
public  void setMyblob ( byte [] _myblob) {
       
this ._myblob = _myblob;
    }


   
public  boolean equals (Object obj) {
       
if ( null  == obj) return  false ;
       
if ( ! (obj instanceof bo.base.BaseBlobTest)) return  false ;
       
else {
            bo.base.BaseBlobTest mObj
= (bo.base.BaseBlobTest) obj;
           
if ( null  ==  this .getId() ||  null  == mObj.getId()) return  false ;
           
else  return ( this .getId().equals(mObj.getId()));
        }
    }


   
public  int hashCode () {
       
if (Integer.MIN_VALUE ==  this .hashCode) {
           
if ( null  ==  this .getId()) return  super .hashCode();
           
else {
                String hashStr
=  this .getClass().getName() +  " : "  +  this .getId().hashCode();
               
this .hashCode = hashStr.hashCode();
            }
        }
       
return  this .hashCode;
    }


   
public String toString () {
       
return  super .toString();
    }

}
package old;


/**
* This is the object class that relates to the blob_test table.
* Any customizations belong here.
*/
public  class BlobTest extends BaseBlobTest {

/* [CONSTRUCTOR MARKER BEGIN] */
   
public BlobTest () {
       
super ();
    }

   
/**
     * Constructor for primary key
    
*/
   
public BlobTest (java.lang.Integer _id) {
       
super (_id);
    }
/* [CONSTRUCTOR MARKER END] */
}


如果还有什么问题,请留言。(2007-10-11 by rosen jiang)

请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处: http://www.blogjava.net/rosen

posted on 2005-08-12 15:06 Rosen 阅读(8795) 评论(8)  编辑  收藏 所属分类: O/R Mapping

评论

# re: Hibernate、iBATIS 与 BLOB 2006-05-15 11:40 yangzhihuan
请问,如果是iBATIS SQL Maps 与 SQL Server BLOB ,那么 <resultMap id="get-blob-result" class="bo.BlobTest">
<result property="id" column="id"/>
<result property="myblob" column="myblob"
typeHandler="com.ibatis.sqlmap.engine.type.BlobTypeHandlerCallback"/>
</resultMap>

这里应该怎么样配置呢??
只是使用java.sql.blob类就成了么???  回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB 2006-05-15 21:31 Rosen
yangzhihuan 你好,BlobTest 对象所包含的 myblob 属性是字节数组类型的,具体可在本文中找到,这部分还是写得很仔细了。由于本文是去年初撰写的,不知道现在最新的 iBatis 是否在处理 LOB 方面有所进步。  回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB 2006-12-07 16:31 jiniwang
非常感谢,但是其中有一些问题,ibatis 在 insert 的时候,如果数据量过大就会报错,超过2000大小。
你可以尝试一下,如果有解决办法,请通知我 jini_wang@hotmail.com  回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB 2006-12-08 00:53 Rosen
@jiniwang
:) 想不到这篇 05 年初的文章还在为大家服务,我很高兴。超过 2K 的问题请换数据库驱动,因为我在测试 HB/Oracle 的时候出现过这种情况(本文中也提到了有 4K 限制)。另外,我记得当时测试的时候我是存储的一张照片,大约 600K,所以应该不是代码或 iBATIS 自身的问题。
  回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB[未登录] 2007-10-11 15:56 phoenix
请问大哥,你发表的关于Hibernate存取SQL server2000中Blob字段的程序中BlobTest何在?内容是什么,里面隐藏了Java流向Blob的转换过程,请不吝赐教!我的邮箱为:jiphoenixsoft@163.com,望看到后回复,谢谢!急!!!!!  回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB 2007-10-11 19:13 Rosen
@phoenix
我回去找找,然后发给你,顺便我也提交到本文中。   回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB 2011-07-08 22:03 陈思
怎么后面的几个类是一样的?就是BaseBlobTest两个一样啊,只是包不一样
我是新手最近遇到这个问题,不是很明白?  回复  更多评论
 

# re: Hibernate、iBATIS 与 BLOB 2011-07-08 22:33 陈思
明白了,唉,我好菜  回复  更多评论
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值