您的位置:首页 > 数据库 > Oracle

java存取oracle中的COLB类型数据

2013-03-10 11:35 363 查看
 一、如何去处理Clob、BLOB的大类型
  CLOB可用于存放大文本数据,最多可存储4GB数据,在应用开发中比较常见.java提供的sql.Clob类与之对应.它提供两个方法来读取Clob的数据:
  getCharacterStream() 方法返回按unicode编码的输入流(java.io.Reader对象)
  getAsciiStream() 方法返回按ASCII编码的输入流(java.io.InputStream对象)
  所以如果你的数据库中有可能存储中文字符的话,就要使用前一个方法.
  现在举一个实际的例子,让我一步步学习如何使用CLOB.
  首先,创建一个含CLOB字段的表:
  create
table test (id
INTEGER,content clob);
  接下来, 我们通过JSP往这张表里插入一条记录,然后再获取显示它.
  插入操作:
  以上需要注意的几点是:
  1)clob类型的数据不能直接insert,要先通过empty_clob()方法给它分配一个locator(同理,blob的用empty_blob()函数分配locator).然后把它select出来(此时它当然没有数据,但结果集不是空的),得到一个Clob的对象,修改该对象的内容让它满足我们的需要,再通过update方法更新该行记录.
  2) 通过select修改含lob类型的记录时一定要锁定该行(通过for update关键字实现),否则oracle会报错.
  3) 刚插入的记录就select for update, 会出现"违反读取顺序"错误,解决办法是将自动提交功能置为false,即不允许自动提交,然后commit它,再select,就可以了.
这就是上面那段代码里//*两行的作用.
  下面,我们将刚插入的记录从数据库中读取出来并显示之:
  二、编码问题
  因为JAVA的开发者是老外,所以他们对中文的支持并不是太好,这一点让不少的我们感到很是头痛,也就是我们通过说的汉字编码问题吧,关于一些汉字编码的规范我就不多说了,我主要是谈谈在和oracle数据库连接时的一些小问题,不过这些小问题很是让人头痛的。
  1、在插入到数据库中的中文问题要转换成编码
  2、从数据库中读到中文又要转换成编码
  让我们看一个编码的JAVA代码:

//ECov.java

  import java.io.UnsupportedEncodingException;

  public class ECov

  {

  public static String asc2gb(String asc){

  String ret;

  if(asc==null)return asc;

  try{

  ret=new String(asc.getBytes("ISO8859_1"),"GB2312");

  }

  catch(UnsupportedEncodingException e){

  ret=asc;

  }

  return ret;

  }

  public static String gb2asc(String gb){

  String ret;

  if(gb==null)return gb;

  try{

  ret=new String(gb.getBytes("GB2312"),"ISO8859_1");

  }

  catch(UnsupportedEncodingException e){

  ret=gb;

  }

  return ret;

  }

  public static int byte2int(byte b){

  return ((-1)>>>24)&b;

  }

  }
  其实这段代码的意思也就是把两种方法合而为一了。
  在进行数据库插入时要用ECov.gb2asc(arg),要在读时要用ECov.asc2gb(arg)。其中最关键的一点就是Oracle好像只认识ISO8859_1这种格式的编码吧(仅是我的想法)。
  三、一些小细节
  1、就是setAutoCommit(true or false),就是我们在sqlPlus中常用commit()的功能,如果是用true,就不要用commit(),否则还是用commit()方法的。
  2、对日期类型的处理,其实他并不是想象中setDate(),getDate()那么简单的,中间有很大的漏洞。大家自己多调试就会觉得有很多的乐趣的。
  3、在和数据库中最好是采用连接池技术,用标准的J2EE的环境,用简单的JNDI技术,是很好的一种方法的。
共2页。
首页
上一页1
2

*操作oracle数据库的CLOB字段,包括读和写

*作者:令少爷

* */

package com.nes.common.sql.lob;

import java.sql.*;

import java.io.*;

import oracle.jdbc.OracleResultSet;

import oracle.sql.*;

public class JClob {

String tableName = null; //表名

String primaryKey = null; //表的主键名

String primaryValue = null; //表的主键值

String fieldName = null; //表的CLOB字段名

String clobValue = null; //表的CLOB字段值

Connection conn = null; //与oracle的连接

/**

*

*用于测试用

*

* */

public static void main(String[] args) {

try {

JClob jc = newJClob(getConnection(),"aa","a","aaaa","c","ccc");

jc.write();

jc.read();

}

catch (Exception e) {

System.out.println(e);

e.printStackTrace();

}

}

/**

*

*构造方法

*

* */

public JClob(Connection connection,String tableName,String primaryKey,StringprimaryValue,String fieldName,String clobValue) {

this.conn = connection;

this.tableName = tableName;

this.primaryKey = primaryKey;

this.primaryValue = primaryValue;

this.fieldName = fieldName;

this.clobValue = clobValue;

}

/**

*

*构造方法,但不必传clobValue值

*一般构造出的实例用来读Clob字段

*

* */

public JClob(Connection connection,String tableName,String primaryKey,StringprimaryValue,String fieldName) {

this.conn = connection;

this.tableName = tableName;

this.primaryKey = primaryKey;

this.primaryValue = primaryValue;

this.fieldName = fieldName;

}

/**

*

*用于测试

*

* */

public static Connection getConnection() throwsSQLException,ClassNotFoundException {

Class.forName("oracle.jdbc.OracleDriver");

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.18:1521:portal","portal","portal");

return conn;

}

/**

*

*读数据库中clob字段的内容

*@return clob字段值

*

* */

public String read() throws SQLException,IOException {

String rtn = null;

try {

String sql = "select " + fieldName + " from " + tableName +" where " + primaryKey + "=" + primaryValue;

//Connection conn = getConnection();

PreparedStatement pstmt = conn.prepareStatement(sql);

//int v = Integer.parseInt(primaryValue);

//pstmt.setInt(1,v);

ResultSet rs = pstmt.executeQuery();

java.sql.Clob clob = null;

if (rs.next()) {

clob = rs.getCLOB(fieldName);

//clob = ((OracleResultSet)rs).getCLOB(fieldName);

//clob = ((org.apache.commons.dbcp.DelegatingResultSet)rs).getClob(fieldName);

//Reader in = clob.getCharacterStream();

InputStream input = clob.getAsciiStream();

int len = (int)clob.length();

byte[] by = new byte[len];

int i ;//= input.read(by,0,len);

while(-1 != (i = input.read(by, 0, by.length))) {

input.read(by, 0, i);

}

rtn = new String(by);

}

}

catch (SQLException e){

throw e;

}

catch (Exception ee) {

ee.printStackTrace();

}

return rtn;

}

/**

*

*葱数据库中clob字段的内容

*

* */

public void write() throws SQLException,IOException {

String sql = "update " + tableName + " set " + fieldName +"=empty_clob() where " + primaryKey + "=" + primaryValue;

//Connection conn = getConnection();

conn.setAutoCommit(false);

PreparedStatement pstmt = conn.prepareStatement(sql);

pstmt.executeUpdate();

sql = "select " + fieldName + " from "+ tableName + " where " + primaryKey + "=" + primaryValue;

Statement st = conn.createStatement();

ResultSet rs = st.executeQuery(sql);

java.sql.Clob clob ;

if (rs.next()) {

clob = ((oracle.jdbc.OracleResultSet)rs).getClob(fieldName);

//clob=((org.apache.commons.dbcp.DelegatingResultSet)rs).getClob(fieldName);

oracle.sql.CLOB my_clob = (oracle.sql.CLOB)clob;

OutputStream writer = my_clob.getAsciiOutputStream();

byte[] contentStr = this.getContent().getBytes();

writer.write(contentStr);

writer.flush();

writer.close();

}

conn.commit();

rs.close();

st.close();

pstmt.close();

conn.setAutoCommit(true);

}

/**

*

*

* */

private String getContent() {

return this.clobValue;

}

/**

*

*

* */

public void setClobValue(String clobValue) {

this.clobValue = clobValue;

}

}

字段类型:blob,clob,nclob

  说明:三种大型对象(LOB),用来保存较大的图形文件或带格式的文本文件,如Miceosoft Word文档,以及音频、视频等非文本文件,最大长度是4GB。LOB有几种类型,取决于你使用的字节的类型,Oracle 8i实实在在地将这些数据存储在数据库内部保存。可以执行读取、存储、写入等特殊操作。

  

  我们所操作的clobtest_table中属性是(字符型id,CLOB型picstr),目前我们假设一个大的字符对象str已经包含了我们需要存入picstr字段的数据。而且connection对象conn已经建立。以下的例子程序也因为不想占用太多的空间,所以对抛出异常没有写。大家参考一下api doc。就可以知道该抛出什么异常了,此处仅仅告诉大家如何去写。

 

  代码:

  (1)对数据库clob型执行插入操作

  *************************************************

  

  java.sql.PreparedStatement pstmt = null;

  ResultSet rs = null;

  String query = "";

  

  conn.setAutoCommit(false); www@bitscn@com

   query = "insert intoclobtest_table(id,picstr) values(?,empty_clob())";

  java.sql.PreparedStatement pstmt =conn.prepareStatement(query);

  pstmt.setString(1,"001");

  pstmt.executeUpdate();

  pstmt = null

   query = "select picstr from clobtest_tablewhere id = '001' for update";

  pstmt = con.prepareStatement(query)

  rs= pstmt.executeQuery();

  

  oracle.sql.CLOB clobtt = null;

  if(rs.next()){

   clobtt = (oracle.sql.CLOB)rs.getClob(1);

  }

  Writer wr = clobtt.getCharacterOutputStream();

  wr.write(strtmp);

  wr.flush();

  wr.close();

  rs.close();

  con.commit();

  

  

  

  (2)通过sql/plus查询是否已经成功插入数据库

  *************************************************

  

  PL/SQL的包DBMS_LOB来处理LOB数据。察看刚才的插入是否成功。使用DBMS_LOB包的getlength这个procedure来检测是否已经将str存入到picstr字段中了。如:bitsCN.nET*中国网管博客

  

  SQL> select dbms_lob.getlength(picstr) fromclobtest_table;

  

  

  (3)对数据库clob型执行读取操作

  *************************************************

  

  读取相对插入就很简单了。基本步骤和一半的取数据库数据没有太大的差别。

  String description = ""

   query = "select picstr from clobtest_tablewhere id = '001'";

  pstmt = con.prepareStatement(query);

  ResultSet result = pstmt.executeQuery();

  if(result.next()){

   oracle.jdbc.driver.OracleResultSet ors =

   (oracle.jdbc.driver.OracleResultSet)result;

   oracle.sql.CLOB clobtmp = (oracle.sql.CLOB)ors.getClob(1);

  

   if(clobtmp==null || clobtmp.length()==0){

   System.out.println("======CLOB对象为空 ");

   description = "";

   }else{

  description=clobtmp.getSubString((long)1,(int)clobtmp.length()); BBS.bitsCN.com网管论坛

   System.out.println("======字符串形式 "+description);

   }

  }
[/size]程序示例:
Java代码

public void getTpxw() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
Query q = session
.createQuery("select infos.guId, infos.subject,infos.content from Infos as infos,Category as category "
+ "where (category.categoryName='视频介绍') and (infos.categoryId=category.guId) "
+ "order by infos.startDate desc ");
q.setFirstResult(0);
q.setMaxResults(1);
Iterator list = q.list().iterator();
Infos infosCustom = null;
if (list.hasNext()) {
Object[] it = (Object[]) list.next();
infosCustom = new Infos();
infosCustom.setGuId((String) it[0]);
String sub = (String) it[1];
// String content = (String) it[2];
infosCustom.setSubject(sub);

try {
SerializableClob bookCol = (SerializableClob) it[2];
Clob jbookColClob = bookCol.getWrappedClob();
CLOB oClob = (CLOB) jbookColClob;
Reader in = oClob.characterStreamValue();
char b[] = new char[8192];
StringBuffer str = new StringBuffer();
long totalSize = 0;
long fileLength = jbookColClob.length();
int ii = 0;
if (fileLength < 8192) {
ii = in.read(b, 0, (int) fileLength);

str.append(b);
} else
while (totalSize < fileLength) {
ii = in.read(b, 0, 8192);
totalSize += ii;
str.append(b);
}
in.close();
infosCustom.setBookColS(str.toString());
String content = str.toString();
if (content != null) {
if (content.length() <= Integer
.parseInt(getContentLength()))
infosCustom.setBookColS(content);
else
infosCustom.setBookColS(content.substring(0, Integer
.parseInt(getContentLength()))
+ "......");
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
infosCustom = new Infos();
infosCustom.setBookColS("没有相关内容");
}
setCurrentTpxw(infosCustom);
tx.commit();
HibernateUtil.closeSession();
}

相关文章:

Clob的解决方法

我也来谈谈Blob、Clob类型字段的读取、保存更新

使用JDBC和Hibernate来写入Blob型数据到Oracle中

推荐圈子: liferay

更多相关推荐
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的“手气不错”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: