• Oracle 的Blob使用小结


    Oracle 的Blob
     
    Oracle的Lobs的流处理方式与Long等对象的Stream方式不一样,没有Long的诸多限制;只要保持连接,就能通过blob对象正确读取对象。
    有两种方式可以读取Blob:
    1.直接使用ps.getBinaryStream()的方法得到流对象
    2.使用getBlob得到blob,然后通过blob的方法提供的getBinaryStream(),getBytes() 访问blob的数据。
    这两种方法都可以在rs.close之后正确获取数据。(在spring 的JdbcTemplet环境下,该rs理论上被JdbcTemplet自动关闭;从数据库连接来看,连接也正确关闭了)。
     
    使用Blob的好处是,按需获取Blob对象。而且可以多次通过blob.getBinaryStream得到对象。且Blob返回的对象可以使用mark/reset方法反复访问。且连接状态正常。
    使用blob得到InputStream,可以调用close()接口,也可以不调用该接口,tb在连接关闭时将自动关闭该连接。最好调用close()释放资源。
     
    c3p0的setBlob(pos,InputStream)接口不能正常工作。
     
    写入或更新Blob时,可以使用ps.setBinaryStream();调用此接口后,in对象到文件尾(在把stream写入blob后,不能要再调用in.close()关闭文件,否则报错)。
    也可以使用setBlob(pos,Blob)方法来写入或更新Blob字段;但是注意的是,无论是以blob还是blob.getBinaryStream的方式,都不能自己更新自己,否则死锁。
     
    使用spring读取blob的示例程序:
                String sql = "select photo from my_photoes where id='test2' and photo is not null and rownum<2 ";
    BLOB blob= (BLOB) simpleDao.queryForObject(sql,Blob.class);        
    InputStream in = blob.getBinaryStream();
    String filename = "./test/dao/pic" + 1+ ".gif";
    BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename));
     
                /* 需oracle的BLOB支持。效率可能会高些,但是空间上会有些浪费
    byte[] b = new byte[blob.getBufferSize()];                //blob必须为oracle.sql.BLOB时才可调getBufferSize方法; 与java.sql.Blob区别。
    System.out.println("bufferSize="+b.length);            //32k左右,用这种方式读取文件会有一点空间的浪费。
    int len=-1;
    while ((len = in.read(b)) != -1) {
    out.write(b);
    }
                */
     
                /*   纯jdbc方法:
                    nt b;
         while ((b = in.read()) != -1) {
        out.write(b);
         }
                */
     
    in.close();
    out.close();
     
     
     
    http://hi.baidu.com/hexiong/blog/item/34d7b2b7f9b3e8f431add103.html  其他参考
    BLOB处理遇到的问题:
    1.用spring的模板类来处理blob时,遇到大文件时,流会异常关闭。解决办法,使用oracle的本地连接来获取blob流,如下:
        public boolean queryForBlobStream(String sql,OutputStream fout)
        {
            boolean flag=true;
            try {
                Connection conn = DataSourceUtils.getConnection(getJdbcTemplate().getDataSource());
                conn.setAutoCommit(false);                        //此部分ms能提高性能
                Statement st = conn.createStatement();
                ResultSet rs = st.executeQuery(sql);
                if (rs.next()) {
                    java.sql.Blob blob = rs.getBlob(1);
                    InputStream ins = blob.getBinaryStream();
                    //输出到文件
                    //下面将BLOB数据写入文件
                    byte[] b = new byte[1024];
                    int len = 0;
                    while ((len = ins.read(b)) != -1) {
                        fout.write(b, 0, len);
                    }
                    //依次关闭
                    fout.close();
                    ins.close();
                }
                conn.commit();
                rs.close();             //maybe not nessesary
                st.close();             //maybe not nessesary
                conn.close();
            } catch (IOException ex) {
                flag=false;
            } catch (SQLException ex) {
                flag=false;
            }
            return flag;
        }
    2.如果把blob对象放到记录的字段中,在web开发中,通过blob.getBinaryStream()只能获得一次blob流,第二次调用同一对象的blob流会得到null流。
    且在这种方式下,不能使用in.close()关闭流。
     
     
     
    **********************************************************
    Oracle中Blob和Clob的作用?
    Blob是指二进制大对象也就是英文Binary Large Object的所写,而Clob是指大字符对象也就是英文Character Large Object的所写。由此可见这辆个类型都是用来存储大量数据而设计的,其中BLOB是用来存储大量二进制数据的;CLOB用来存储大量文本数据。
    那么有人肯定要问既然已经有VARCHAR和VARBINARY两中类型,为什么还要再使用另外的两种类型呢?其实问题很简单,VARCHAR 和VARBINARY两种类型是有自己的局限性的。首先说这两种类型的长度还是有限的不可以超过一定的限额,以VARCHAR再ORA中为例长度不可以超过4000;那么有人又要问了,LONGVARCHAR类型作为数据库中的一种存储字符的类型可以满足要求,存储很长的字符,那为什么非要出现CLOB类型呢?其实如果你用过LONGVARCHAR类型就不难发现,该类型的一个重要缺陷就是不可以使用LIKE这样的条件检索。(稍候将介绍在CLOB中如何实现类似LIKE的模糊查找)另外除了上述的问题外,还又一个问题,就是在数据库中VARCHAR和VARBINARY的存取是将全部内容从全部读取或写入,对于100K或者说更大数据来说这样的读写方式,远不如用流进行读写来得更现实一些。
    在JDBC中有两个接口对应数据库中的BLOB和CLOB类型,java.sql.Blob和java.sql.Clob。和你平常使用数据库一样你可以直接通过ResultSet.getBlob()方法来获取该接口的对象。与平时的查找唯一不同的是得到Blob或Clob的对象后,我们并没有得到任何数据,但是我们可以这两个接口中的方法得到数据
    例如:
    Blob b=resultSet.getBlob(1);
    InputStream bin=b.getBinaryStryeam();
    Clob c=resultSet.getClob(2);
    Reader cReader=c.getCharacterStream():
    关于Clob类型的读取可以使用更直接的方法,就是直接通过ResultSet.getCharacterStream();方法获得字符流,但该方法并不安全,所以建议还是使用上面例子的方法获取Reader。
    另外还有一种获取方法,不使用数据流,而是使用数据块。
    例如
    Blob b=resultSet.getBlob(1);
    byte data=b.getByte(0,b.length());
    Clob c=resultSet.getClob(2);
    String str=c.getSubString(0,c.length()):
    在这里我要说明一下,这个方法其实并不安全,如果你很细心的话,那很容易就能发现getByte()和getSubString()两个方法中的第二个参数都是int类型的,而BLOB和CLOB是用来存储大量数据的。而且Bolb.length()和Clob.length()的返回值都是 long类型的,所以很不安全。这里不建议使用。但为什么要在这里提到这个方法呢?稍候告诉你答案,这里你需要记住使用数据块是一种方法。
     
    在存储的时候也同样的在PreparedStatement和CallableStatememt中,以参数的形式使用setBlob()和 setClob方法把Blob和Clob对象作为参数传递给SQL。这听起来似乎很简单对吧,但是并非我们想象的这样,很不幸由于这两个类型的特殊,JDBC并没有提供独立于数据库驱动的Blob和Clob建立对象。因此需要自己编写与驱动有关的代码,但这样又牵掣到移植性。怎样才是解决办法呢?这就要用到前面说过的思想了使用数据块进行写操作。同样用PreparedStatement和CallableStatememt类,但参数的设置可以换为setAsciiStream、setBinaryStream、setCharacterStream、setObject(当然前3个同样存在长度的问题)
    下面给大家个例子以方便大家理解
    public void insertFile(File f)  throws Exception{
    FileInputStream fis=new FileInputStream(f,Connection conn);
    byte[] buffer=new byte[1024];
    data=null;
    int sept=0;int len=0;
     
    while((sept=fis.read(buffer))!=-1){
    if(data==null){
    len=sept;
    data=buffer;
    }else{
    byte[] temp;
    int tempLength;
     
    tempLength=len+sept;
    temp=new byte[tempLength];
    System.arraycopy(data,0,temp,0,len);
    System.arraycopy(buffer,0,temp,len,sept);
    data=temp;
    len=tempLength;
    }
    if(len!=data.length()){
    byte temp=new byte[len];
    System.arraycopy(data,0,temp,0,len);
    data=temp;
    }
    }
    String sql="insert into fileData (filename,blobData) value(?,?)";
    PreparedStatement ps=conn.prepareStatement(sql);
    ps.setString(1,f.getName());
    ps.setObject(2,data);
    ps.executeUpdate();
     
    }
     
    最后由于刚刚说过Clob类型读取字符的长度问题,这里再给大家一段代码,希望对你有帮助
    public static String getClobString(ResultSet rs, int col) {
    try {
    Clob c=resultSet.getClob(2);
    Reader reader=c.getCharacterStream():
    if (reader == null) {
    return null;
    }
    StringBuffer sb = new StringBuffer();
    char[] charbuf = new char[4096];
    for (int i = reader.read(charbuf); i > 0; i = reader.read(charbuf)) {
    sb.append(charbuf, 0, i);
    }
    return sb.toString();
    } catch (Exception e) {
    return "";
    }
    }
     
    另外似乎前面还提到过LIKE检索的问题。LONGVARCHAR类型中不可以用LIKE查找(至少ORA中不可以使用,其他的数据库我没有试过),在ORA中我们可以使用这样一个函数dbms_lob.instr来代替LIKE来个例子吧
     
    select docid,dat0 from text where dbms_lob.instr(dat0,'魏',1,1)>0
     
    在text表中有两个字段docid用来放文档编号dat0为clob类型存放文章内容;这句话的意思就是检索第一条dat0中出现第一次"魏"字的数据。听起来这个检索的数据有点象google的“手气不错”
  • 相关阅读:
    获取自己的网络出口IP地址
    go语言开发IDE
    国内可用的python源
    Tomcat 配置及优化
    大小不固定的图片和多行文字的垂直水平居中
    行内元素与块级元素比较全面的区别和转换
    常用的四种CSS样式表格
    JS鼠标事件大全
    Javascript 5种方法实现过滤删除前后所有空格
    JavaScript trim 实现(去除字符串首尾指定字符)
  • 原文地址:https://www.cnblogs.com/huapox/p/3251514.html
Copyright © 2020-2023  润新知