`

从 Oracle 大字段(blob,clob)的读、写认识 Java JDBC操作全攻略

    博客分类:
  • J2SE
阅读更多
JDBC(Java Database Connectivity) 是 Sun 公司提供的一套通过对各个数据库厂商提供的函数进行整合和抽象的一族数据库操作类。
它们是Java2标准平台版本的一部分。JDBC 把对数据库的连接大致分成了两大类:
                
                 1.通过 JDBC-ODBC 桥连接数据库
                 2.通过 JDBC 连接数据库
 
由于 JDBC-ODBC 连接数据库效率低下,因此,在大多数项目中 JDBC-ODBC 一般不是项目的开发首选,除非你的库用的是 M$ 的 Access ,没办法 M$ 就是这么霸道!哈哈。
 
组成 JDBC API 的类和接口包含在java.sql和java.text包中。
 
(1)建立连接:
 
首先必须使用Class.forName(String dbDriverClassname)方法检查是否安装了适当的JDBC驱动程序。这个方法是用来动态加载类的,dbDriverClassname是驱动程序类的名称。加载了驱动程序后,使用java.sql包中的DriverManager类中的getConnection()方法可以建立数据库连接,这个方法有三种形式:
java 代码
  1. public static synchronized Connection getConnection(String url) throws SQLException   
  2. public static synchronized Connection getConnection(String url,String user,String pwd)  throws SQLException   
  3. public static synchronized Connection getConnection(String url, java.util.Properties info) throws SQLException  
(2)执行SQL语句并取回结果:
 
创建了数据库连接后,当我向数据库库发出一个SQL查询时,首先要做的事情是使用Connection对象的方法创建一个Statement、PreparedStatement或者CallableStatemet;一旦有了这些语句(statement)对象中的任一个,就可以执行该语句并通过ResultSet对象读出查询结果(如果查询有返回结果的话)。
 
java 代码
  1. Statement createStatement() throws SQLException   
  2. Statement createStatement(int resultSetType , int resultSetConcurrency) throws SQLException   
  3. PreparedStatement prepareStatement(String sql) throws SQLException   
  4. PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException   
  5. CallableStatement prepareCall(String sql) throws SQLException   
  6. CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException  
在对 BLob 和 Clob 型字段进行读写操作时,需要一个可以生成可滚动和/或可更新的 ResultSet 对象,否则 JRE 会告诉你“记录没有锁定”。但是,默认的 ResultSet 对象不可更新,仅有一个向前移动的指针。因此,只能迭代它一次,并且只能按从第一行到最后一行的顺序进行。因此,你需要使用下面的方式产生一个 ResultSet 对象:
java 代码
  1. Statement stmt = con.createStatement(   
  2.                                ResultSet.TYPE_SCROLL_INSENSITIVE,   
  3.                                ResultSet.CONCUR_UPDATABLE);   
  4. ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");   
  5. // rs will be scrollable, will not show changes made by others,   
  6. // and will be updatable  

 
 
 
你可能对上面加粗的代码感到疑惑,没关系,我这里将其所有的可用参数做了一个总结:
 

CLOSE_CURSORS_AT_COMMIT
          该常量指示调用 Connection.commit 方法时应该关闭 ResultSet 对象。

CONCUR_READ_ONLY
          该常量指示不可以更新的 ResultSet 对象的并发模式。

CONCUR_UPDATABLE
          该常量指示可以更新的 ResultSet 对象的并发模式。

FETCH_FORWARD
          该常量指示将按正向(即从第一个到最后一个)处理结果集中的行。

FETCH_REVERSE
          该常量指示将按反向(即从最后一个到第一个)处理结果集中的行处理。

FETCH_UNKNOWN
          该常量指示结果集中的行的处理顺序未知。

HOLD_CURSORS_OVER_COMMIT
          该常量指示调用 Connection.commit 方法时不应关闭 ResultSet 对象。

TYPE_FORWARD_ONLY
          该常量指示指针只能向前移动的 ResultSet 对象的类型。

TYPE_SCROLL_INSENSITIVE
          该常量指示可滚动但通常不受其他的更改影响的 ResultSet 对象的类型。

TYPE_SCROLL_SENSITIVE
          该常量指示可滚动并且通常受其他的更改影响的 ResultSet 对象的类型。

 
这些常量都属于 ResultSet 类为:static int型。
有了上面的这些基础,接下来我们就可以利用 Java 代码在 Oracle 库中记录 CLob / BLob 型数据了。
 
首先来说明 BLob 型数据和 CLob 型数据的差别:在 Oracle 中 BLob 型的字段主要用来记录二进制数据,如:图片、媒体、音乐以及压缩文件等等等等……。而 Clob 主要用来记录大字段的文本信息。
 
我首先想说明一下如何来写入 CLob 型数据之后说明如何往 BLob 中写值。
 
1.为了数据量足够大,因此我生成一个大约 2.5MB 的随机字母序列用以写入数据库:
java 代码
  1. char mychar='A';   
  2. char thechar;   
  3. StringBuffer strB=new StringBuffer();   
  4. for(int i=0;i<=100000;i++){   
  5.     for(int j=0;j<26;j++){   
  6.         int myRandom=(int)((100*(Math.random()))%26);   
  7.         thechar=(char)(myRandom+mychar);   
  8.         strB.append(thechar);   
  9.     }   
  10. }  
 
 
2.开始入库:
java 代码
  1. public void setClob(String values) throws Exception{   
  2.         try{   
  3.                 conn=DBConnection.getConn();   
  4.                 ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);   
  5.                 conn.setAutoCommit(false);   
  6.                 rs=ps.executeQuery("select clobid, mydata from myclob where clobid='1111' for update");   
  7.                 java.sql.Clob clob=null;   
  8.                 if(rs.next()){   
  9.                         clob=rs.getClob("mydata");   
  10.                         CLOB myclob=(CLOB)clob;   
  11.                         Writer outStream=myclob.getCharacterOutputStream();   
  12.                         char[] c=values.toCharArray();   
  13.                         outStream.write(c,0,c.length);   
  14.                         outStream.flush();   
  15.                         outStream.close();   
  16.                 }   
  17.                 conn.commit();   
  18.         } catch(Exception e){   
  19.                 e.printStackTrace();   
  20.                 conn.rollback();   
  21.                 e.getMessage();   
  22.                 throw new Exception(e);   
  23.         } finally{   
  24.                 DBConnection.close(rs);   
  25.                 DBConnection.close(ps);   
  26.                 DBConnection.freeConn(conn);   
  27.         }   
  28. }  
接下来,我对 setClob(String values) 方法开始进行分析:
 
为了能够正确将大字段写入 Oracle 库中,在执行写入之前你还需要作一点小小的准备性工作 :
 
java 代码
  1. public void clearClob()throws Exception{   
  2.     try{   
  3.         Connection conn=DBConnection.getConn();   
  4.         Statement ps=conn.createStatement();   
  5.         String updateSQL="update myclob set mydata=empty_clob() where clobid='1111'  and mydata is null";   
  6.         ps.executeUpdate(updateSQL);   
  7.     } catch(Exception ex){   
  8.         ex.printStackTrace();   
  9.         throw new Exception(ex);   
  10.     } finally{   
  11.         //close RS/PS/DB   
  12.     }   
  13. }  
因为在默认情况下 Clob 对象是 Null 型的,对一个 Null 型对象在进行操作时会抛出“空指针异常”因此,我们需要在该字段写入一个空 Clob 对象。下面我开始对数据的提交的方法进行分析说明:
 
java 代码
  1. ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);  
上面的这行代码现在应该不需要再进行详细的说明了吧。
 
在锁定单行记录的情况下,只能采用连接(conn)提交方式而不是记录集(ps)提交方式。在默认情况下,连接提交方式被设置在了AutoCommit状态下,因此,为了能够使我们更新的数据能够在连接提交方式下进行提交,就需要将AutoCommit状态设置为 false 。
 
剩下的问题就是“for update”关键字,通常,SELECT操作将不会对正处理的行执行任何锁定设置,这使得连接到该数据库的其他会话可以改变正在选择的数据。
但是,结果集仍然是一致性的。当确定了活动集以后,在执行OPEN的时刻,ORACLE会截取下该表的一个快照。在此时刻以前所提交的任何更改操作都会在活动集中反映出来。在此时刻以后所进行的任何更改操作,即使已经提交了它们,都不会被反映出来,除非将该游标重新打开。但是使用 FOR UPDATE 子句,在OPEN返回以前的活动集的相应行上会加上互斥锁,这些锁会避免其他的会话对活动集中的行进行更改。直到整个事务被提交为止。因此,为了确保活动集的相应行被锁定,我们需要在 select 语句中加入 FOR UPDATE 子句。
 
接下来就是将大字段数据入库,这里牵扯到一个输入/输出流的概念,为了保证这个主题的完整性,这个问题我不打算在这个主题中进行阐述,我会在近期单开一个主题来专门讨论有关 Java 中的 Write 和 Reader 在 I/O 处理中的应用。同时,我也会对这里的 I/O 处理问题作一个完整的解答。
 
好了,现在我们期待已久的大字段已经被我们写入到了数据库中,那么怎么样才能把它从库中读出来并显示出来呢,接下来,我将对这个问题作一个比较完整的实现说明。
 
以下是读取 Clob 对象的完整操作方法:
java 代码
  1. public String showClob() throws Exception{   
  2.         try{   
  3.                 String str=null;   
  4.                 conn=DBConnection.getConn();   
  5.                 ps=conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,java.sql.ResultSet.CONCUR_READ_ONLY);   
  6.                 rs=ps.executeQuery("select clobid, mydata from myclob where clobid='1111' ");   
  7.                 java.sql.Clob clob=null;   
  8.             if(rs.next()){   
  9.                     clob=rs.getClob("mydata");   
  10.                     CLOB myclob=(CLOB)clob;   
  11.                     long clen=myclob.length();   
  12.                     char clobArray[] = new char[(int)clen];   
  13.                     int readednum= myclob.getChars(1,(int)clen,clobArray);   
  14.                     StringBuffer sb=new StringBuffer();   
  15.                     sb.append(clobArray);   
  16.                     str=sb.toString();   
  17.             }   
  18.             return str;   
  19.         } catch(Exception e){   
  20.                 e.printStackTrace();   
  21.                 e.getMessage();   
  22.                 throw new Exception(e);   
  23.         } finally{   
  24.                 //close RS/PS/DB   
  25.         }   
  26. }  
首先对以下两行代码进行比较:
 
java 代码
  1. ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY   
  2. ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE  
 
在向数据库中写入 Clob 对象时,为了我们的写入操作不受影响就需要锁定单行记录,因此使用 TYPE_SCROLL_INSENSITIVE 型 ResultSet 对象
………………………………………………未完待续!
分享到:
评论
2 楼 pengsuyun 2009-11-04  
很牛逼!向你学习
1 楼 为一碗饭而奔 2007-12-20  
clob.getCharacterOutputStream();   //此方法已不推荐使用,但还是可以使用的,不知道被什么方法给替换掉了呀,可以告诉我吗?谢谢

相关推荐

    图片存入Oracle中,用clob和blob两种方式

    - **准备环境**:首先确保已经安装了Oracle数据库客户端和相应的驱动程序,例如JDBC驱动,以便通过编程语言(如Java、Python等)与数据库交互。 - **连接数据库**:使用相应的连接字符串、用户名和密码建立与...

    jdbc批量插入大字段

    因此,"jdbc批量插入大字段"这个话题旨在探讨如何高效地通过Java JDBC来实现Blob字段的批量插入,以提高性能。 首先,我们需要了解JDBC(Java Database Connectivity),它是Java编程语言与各种数据库之间通信的...

    ORACLE数据库中插入大字段数据的解决方法

    在ORACLE数据库中插入大字段数据时,可能会遇到性能问题或者由于字段长度限制导致的错误。这类问题通常涉及LOB(Large Object)类型的字段,如CLOB(Character Large Object)和BLOB(Binary Large Object)。本篇...

    oracle数据库的clob大字段在jdbc中的处理方式

    在Java中,当我们需要通过JDBC(Java Database Connectivity)接口与Oracle数据库交互时,处理CLOB字段可能会遇到一些挑战。这篇文档将详细阐述如何在JDBC中有效地读取和操作Oracle数据库的CLOB字段,并将其转换为...

    数据库读取clob字段

    下面是一个Java方法`clobRead()`的具体实现,用于从Oracle数据库中读取CLOB字段的内容。 ```java public static String clobRead() throws Exception { DBlo_db = null; String detailinfo = ""; Connection ...

    关于oracle中clob字段查询慢的问题及解决方法

    最近在用oracle的过程中用到了对blob字段模糊查询的问题,对oracle来说,我并不是高手,找了很多的资料终于能够查出来了。 blob字段直接用 select * from table_name where column like ‘%%'查找的时候是不能实现...

    spring+hibernate 解决大字段(clob)

    ### Spring与Hibernate处理大字段(CLOB/BLOB) 在企业级应用开发中,经常会遇到需要存储大量文本或二进制数据的情况,这时就需要用到数据库的大字段类型如CLOB(Character Large Object)和BLOB(Binary Large ...

    jdbc课件以及源代码(数据源)

    **JDBC(Java Database Connectivity)**是Java编程语言中用于规范客户端程序如何访问数据库的应用程序接口,它提供了标准的API让Java程序员能够连接到不同类型的数据库系统,进行数据的增删改查操作,以及事务处理...

    Hibernate操作数据库大字段的示例(附源码及详细开发使用方法)。

    在Hibernate中,我们通常使用`Blob`和`Clob`类型来映射这些大字段。 **一、Hibernate配置** 在Hibernate配置文件(hibernate.cfg.xml)中,确保已经正确设置了数据库连接参数,并且JDBC驱动支持大字段的处理。对于...

    ORALCE10g驱动classes12.jar版本问题 类型长度大于最大值

    在Oracle 10g中,这个JDBC驱动被称为oci.jdbc10g,它负责处理Java应用程序与Oracle数据库之间的数据交换。 当出现“类型长度大于最大值”的错误时,这可能意味着在尝试存储或查询的数据中,某个字段的长度超过了...

    DBKING使用指南

    在dbking中,所有的数据库数据只有五种数据类型,String、Number(BigDecimal)、Timestamp、Clob(String)、Blob(byte[]),经过反复测试后,我们会例出各种数据库数据类型到这五种类型的映射表,当然我们也有...

Global site tag (gtag.js) - Google Analytics