论坛首页 Java版 Spring

谈谈在spring(hibernate)中如何处理oracle大字段

浏览 13537 次
该帖已经被评为精华帖
作者 正文
最后更新时间:2005-10-14
===============================================
在spring中如何处理oracle大字段

  在spring中采用OracleLobHandler来处理oracle大字段(包括clob和blob),则在程序中不需要引用oracle的特殊类,从而能够保证支持我们的代码支持多数据库。

1、首先数据表中的clob类型对应java持久化类的String类型;而blob类型对应byte[]类型
2、定义hibernate标签时,持久化类中对应clob类型的属性的hibernate type应为org.springframework.orm.hibernate.support.ClobStringType;而对应blob类型的属性的hibernate type应为org.springframework.orm.hibernate.support.BlobByteArrayType。
3、以后访问这些对应clob和blob类型的属性时,按普通属性处理,不需要特别编码。
===============================================
请问大家有没有试上面方法在spring中处理Oracle的blob?有这方面经验的朋友说一下怎么实现! 我现在用hibernate操作oracle的blog存取基本是按传统的jdbc方式处理的,如下例子所示。如果用spring提供的org.springframework.jdbc.support.lob.OracleLobHandler类,应该怎么修改! 如果大家有自已更好的方法,请不吝赐教! 3q

例: Customer.hbm.xml
[code:1] <?xml version="1.0"?>

<hibernate-mapping package="com.jandar.bo">
     <class name="Customer" table="CUSTOMER">
<id
        column="ID"
        name="Id"
        type="integer"
>
<generator class="vm" />
</id>
<property
column="NAME"
length="25"
name="Name"
not-null="false"
type="string"
/>
<property
column="IMAGES"
name="Images"
not-null="false"
type="blob"
/>
</class>
</hibernate-mapping>[/code:1]

===============================================


[code:1]import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.List;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.LockMode;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;
import weblogic.jdbc.vendor.oracle.OracleThinBlob;
import com.jandar.bean.ImageBean;
import com.jandar.bo.Customer;
import com.jandar.services.dao.ImageDAO;

public class ImageDAOImpl extends HibernateDaoSupport  
                                           implements ImageDAO{

          byte[] buffer = new byte[10];

          public Customer findImage(Customer customer) {
          String getId = "select max(cu.id) from Customer as cu";
          List list = (List)getHibernateTemplate().find(getId);
     Customer customerBean =
                    (Customer)getHibernateTemplate().load
                    (Customer.class,Integer.valueOf(list.get(0).toString()));
    return customerBean;
      }

       public void saveImages(Object object){
              Customer customer = new Customer();
              ImageBean imageBean = (ImageBean)object;
              OutputStream out = null;
              InputStream fin = null;
              try{
                        //Session session = getSession();
       //session.connection().prepareStatement("insert into ");
                      //Connection connection = null;
     //connection = (Connection)session.connection();
     //PreparedStatement ps = connection.createStatement();
        customer.setName("jack");
        customer.setImages(Hibernate.createBlob(buffer));
           getHibernateTemplate().save(customer);
        getHibernateTemplate().flush();
getHibernateTemplate().refresh(customer, LockMode.UPGRADE);
                //since: weblogic8.2 lib
        OracleThinBlob blob = (OracleThinBlob)customer.getImages();
        out = blob.getBinaryOutputStream();
        String fileName = imageBean.getImageName();
        File f = new File(fileName);
        fin = new FileInputStream(f);
        //int count = -1, total = 0;
       //fin.read(data);
        byte[] data = new byte[ (int) fin.available()];
        int bytesReaded = 0;
              while((bytesReaded=fin.read(data,0,data.length)) != -1) {
          out.write(data, 0, bytesReaded);
}
         //out.write(data);
                           customer.setName(imageBean.getName());
           out.flush();
                           getHibernateTemplate().flush();
                }catch(SQLException sqlError){
                 System.out.println("sql error:  "+ sqlError.getMessage());
}catch(Exception notFound){
              System.out.println("sql error:  "+ notFound.getMessage());
}finally{
                try{
           out.close();
            fin.close();
                }catch(IOException error){
               
                }
            }
      }

}[/code:1]
   
最后更新时间:2005-10-14
[code:1]
<bean id="mySessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="dataSource">
                <ref bean="myDataSource2"/>
         </property>
         <property name="lobHandler">
<ref bean="oracleLobHandle"/>
         </property> 
</bean>
<bean id="nativeJdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"/>

<bean id="oracleLobHandle" class="org.springframework.jdbc.support.lob.OracleLobHandler" Lazy-init="true">
<property name="nativeJdbcExtractor">
    <ref local="nativejdbcExtractor"/>
</property>
</bean>[/code:1]


Spring为处理数据库Lob字段,特别提供了LobHandler接口。在操作Oracle RDBMS过程中,由于Oracle JDBC Driver实现的问题,应用必须采用Oracle原生的数据库连接(比如,oracle.jdbc.OracleConnection)、LOB原生实现(比如,oracle.sql.BLOB、oracle.sql.CLOB)。因此,LobHandler接口存在上述两种实现。简而言之,为操作Oracle数据库,必须使用OracleLobHandler实现。如果操作其他RDBMS类型,则使用DefaultLobHandler。NativeJdbcExtractor是个接口,通过它能够抽象各种连接池。另外Spring还提供两个接口存取Blob,LobCreator及LobHandler

接口LobCreator
[code:1]
     //.....省略某些方法             
     void setBlobAsBytes(PreparedStatement ps, int  paramIndex, byte[] content)throws SQLException;

       void setBlobAsBinaryStream(PreparedStatement ps, int paramIndex,  InputStream contentStream, int contentLength)throws SQLException;[/code:1]


接口LobHandler
[code:1]
     //.....省略某些方法             
          byte[] getBlobAsBytes(ResultSet rs, String columnName)throws SQLException;

byte[] getBlobAsBytes(ResultSet rs, int columnIndex)throws SQLException;

InputStream getBlobAsBinaryStream(ResultSet rs,String columnName) throws SQLException;

InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException;
[/code:1]


我现在自定义一个BinaryBlobType类型,请问怎么同时使用LobHandler和Hibernate UserType实现。它们两者的关联怎么配置才算正确呢?是不是UserType和LobHandler两者只能选择一个?

[code:1]
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 {
        InputStream blobReader = rs.getBinaryStream(names[0]);
        if (blobReader == null)
            return null;
        byte[] b = new byte[1024];

        ByteArrayOutputStream os = new ByteArrayOutputStream();

        try {
            while ((blobReader.read(b)) != -1)
                os.write(b);
        } catch (IOException e) {
            throw new SQLException(e.toString());
        } finally {
            try {
                os.close();
            } catch (IOException e) {
            }
        }
        return os.toByteArray();
    }

       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;
  }

}
[/code:1]
   
0 请登录后投票
最后更新时间:2005-10-14
哪有这么麻烦?不好意思,你贴的实在是太多了,让我失去了看下去的耐心。
spring的sample里面专门有-个操作blob和clob的例子,非常详尽,你看了自然知道如何处理了,我不用在此废话。
   
0 请登录后投票
最后更新时间:2005-10-14
denis 写道
哪有这么麻烦?不好意思,你贴的实在是太多了,让我失去了看下去的耐心。
spring的sample里面专门有-个操作blob和clob的例子,非常详尽,你看了自然知道如何处理了,我不用在此废话。


spring那个imagedb用的是JdbcDaoSupport里的getJdbcTemplate()实现的!没有用hibernate
   
0 请登录后投票
最后更新时间:2005-10-14
sigh.....
楼主,我可以告诉你,如果使用hibernate,那么处理这个问题会更简单更透明,你目前最关键的是要学会如何举一反三。

也罢,贴一些片断,明白就明白了,再不明白俺也帮不了你了,我不多做解释。

另:这些配置片断以及代码片段仅在spring1.1.3,hibernate2.1.3上测试通过。理由嘛,这些都是今年初的一个项目中采用的解决方法,而项目结束时使用的spring的版本是1.1.3,hibernate2.13。现在很久没碰spring以及hibernate了,不知道是不是有了更优雅的解决方法?

LocalSessionFactoryBean配置:
引用
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="lobHandler">
<ref local="oracleLobHandler" />
</property>

<property name="mappingResources">
<list>...</list>
</property>
<property name="hibernateProperties">...</property>
</bean>


lobHandler:
引用
<bean id="oracleLobHandler"
class="org.springframework.jdbc.support.lob.OracleLobHandler"
lazy-init="true">
<property name="nativeJdbcExtractor">
<ref local="nativeJdbcExtractor" />
</property>

</bean>


nativeJdbcExtractor:
引用
<!--使用dbcp连接池时启用-->
<bean id="nativeJdbcExtractor"
class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
lazy-init="true" />
<!--使用websphere连接池时启用
<bean id="nativeJdbcExtractor"
class="org.springframework.jdbc.support.nativejdbc.WebSphereNativeJdbcExtractor"
lazy-init="true"/>
-->



pojo blob字段的xdoclet:
[code:1]
public Class BinaryFile
private byte[] content;
/**
   * @hibernate.property
   * column="content"
   * type="org.springframework.orm.hibernate.support.BlobByteArrayType"
   *
   * @return binary array content
   */
  public byte[] getContent()
  {
    return content;
  }[/code:1]


示例代码调用:
[code:1]File file = some file get from anywhere.........
byte[] fileArray = org.springframework.util.FileCopyUtils.copyToByteArray(file);
BinaryFile bFile = new BinaryFile();
bFile.setContent(fileArray);
getHibernateTemplate().save(bFile);[/code:1]
   
0 请登录后投票
最后更新时间:2005-10-17
denis 写道

pojo blob字段的xdoclet:
[code:1]
public Class BinaryFile
private byte[] content;
/**
   * @hibernate.property
   * column="content"
   * type="org.springframework.orm.hibernate.support.BlobByteArrayType"
   *
   * @return binary array content
   */
  public byte[] getContent()
  {
    return content;
  }[/code:1]


示例代码调用:
[code:1]File file = some file get from anywhere.........
byte[] fileArray = org.springframework.util.FileCopyUtils.copyToByteArray(file);
BinaryFile bFile = new BinaryFile();
bFile.setContent(fileArray);
getHibernateTemplate().save(bFile);[/code:1]


   嗯,多谢denis的指导。在spring1.2和hibernate2.1中也可以通过。看了一下spring和hibernate的源码,无论是自定义的type还是用spring提供的oracleLobHandler最终都要实现org.hibernate.usertype.UserType这个接口。
   
0 请登录后投票
最后更新时间:2005-11-01
denis 用的数据库是8.1.7?

我想应该是9i以上版本吧?我照着denis贴的内容,jdbc driver用过8.1.7、9.2.0.1、9.2.0.3、9.2.0.4、9.2.0.4、9.2.0.5、10.1.0.2、10.1.0.4、10.2.0.1.0,都没办法往CLOB、BLOB里面弄数据进去。之前google或是javaeye上搜到的资料,无一例外的出错。

似乎对于8i来说,唯一有效的,就是先empty_lob(),然后再for update了。
   
0 请登录后投票
最后更新时间:2005-11-02
mmwy 写道
denis 用的数据库是8.1.7?

我想应该是9i以上版本吧?我照着denis贴的内容,jdbc driver用过8.1.7、9.2.0.1、9.2.0.3、9.2.0.4、9.2.0.4、9.2.0.5、10.1.0.2、10.1.0.4、10.2.0.1.0,都没办法往CLOB、BLOB里面弄数据进去。之前google或是javaeye上搜到的资料,无一例外的出错。

似乎对于8i来说,唯一有效的,就是先empty_lob(),然后再for update了。


我的版本是9.0.1.0.0用denis的方法是可以,另外我在mysql4.1上也用该方法通过了!是可以直接往数据库插入CLOB、BLOB的,而不用先empty_lob(),然后再for update
   
0 请登录后投票
最后更新时间:2005-11-02
好贴,长见识了
   
0 请登录后投票
最后更新时间:2005-11-08
8I也可以的,我试过
配置差不多的
   
0 请登录后投票
论坛首页 Java版 Spring

跳转论坛:
JavaEye推荐