一.首先介绍一下CLOB和BLOB
BLOB(Binary Large Object)用于存储二进制数据的大字段类型:例如图片
CLOB(Character Large Object)用于存储字符型数据的大字段类型:例如XML文件
在mysql中已经有VARCHAR和VARBINARY这两种数据类型来分别存储字符型数据和二进制数据。但是以上两种数据有自己的局限性,他们的大小都是有限制的。所以当数据量过大时,需要用大字段类型进行存储。
而在Oracle中只有VARCHAR和BINARY,并没有VARBINARY。在Oracle中一般二进制数据类型就用BLOB表示。(这里再插一句,BINARY(N)和VARBINARY(N)中的N指的是字节长度,而CHAR(N)和VARCHAR(N)中N指的是的字符长度。对于BINARY(10),其可存储的字节固定为10,而对于CHAR(10),其可存储的字节视字符集的情况而定。具体通过后续的实验给出结果,先暂时给出结论)。
二.如何在Oracle中操作CLOB,BLOB
CLOB,BLOB这两种数据库类型在Oracle数据库中的处理比较特殊:oracle中Blob/Clob字段访问的独特方式 oracle中Blob/Clob字段本身就拥有一个游标(cursor),JDBC必须通过游标对该字段进行操作。 在字段创建之前,我们无法获取游标句柄,这意味着,我们必须首先先创建一个空的字段再从这个空的字段中获取游标,写入我们期望保存的数据。(摘自深入浅出Hibernate)
下面来看具体操作代码,先定义一个实体类:
package Blob;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.Clob;
public class UserBlob implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public UserBlob() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Blob getImage() {
return image;
}
public void setImage(Blob image) {
this.image = image;
}
public Clob getResume() {
return resume;
}
public void setResume(Clob resume) {
this.resume = resume;
}
private Integer id;
private String name;
private Blob image;
private Clob resume;
}
再给出操作数据的代码
package Blob;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import oracle.sql.BLOB;
import oracle.sql.CLOB;
import org.junit.Test;
import util.DbHelper;
/**
* @ClassName: BlobTest
* @Description: TODO(这里用一句话描述这个类的作用)
* @author wangcc
* @date 2016-11-25 下午2:55:11
*
*/
public class BlobTest {
public static void main(String[] args) {
insertClob();
}
/**
* @Title: insertClob
* @Description: TODO 摘自深入浅出hibernate 问题在于oracle中Blob/Clob字段访问的独特方式 oracle中
* Blob/Clob字段本身就拥有一个游标(cursor),JDBC必须通过游标对该字段进行操作
* 在字段创建之前,我们无法获取游标句柄,这意味着,我们必须首先先创建一个空的字段
* 再从这个空的字段中获取游标,写入我们期望保存的数据。
*
* @param 设定文件
* @return void 返回类型
* @throws
*/
/**
* @Title: insertClob
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param 设定文件
* @return void 返回类型
* @throws
*/
public static void insertClob() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DbHelper.getConnection();
conn.setAutoCommit(false);
String sql = "insert into user_blob(id,name,image,resume) values(?,?,?,?)";
ps = conn.prepareStatement(sql);
ps.setInt(1, 1);
ps.setString(2, "james");
ps.setBlob(3, BLOB.empty_lob());
ps.setClob(4, CLOB.empty_lob());
ps.executeUpdate();
ps.close();
String sql1 = "select image,resume from user_blob where id=? for update";
ps = conn.prepareStatement(sql1);
ps.setInt(1, 1);
rs = ps.executeQuery();
rs.next();
BLOB blob = (BLOB) rs.getBlob(1);
CLOB clob = (CLOB) rs.getClob(2);
FileInputStream in = new FileInputStream("F:\\CLobTest\\test.txt");
OutputStream out = blob.getBinaryOutputStream();
byte[] buf = new byte[10240];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
in.close();
out.close();
clob.putString(1, "This is my clob");
String sql2 = "update user_blob set image=? and resume=? where id=?";
ps = conn.prepareStatement(sql2);
ps.setBlob(1, blob);
ps.setClob(2, clob);
ps.setInt(3, 1);
ps.executeUpdate();
System.out.println("DONE!");
conn.commit();
System.out.println("DONE!");
} catch (Exception e) {
// TODO: handle exception
} finally {
DbHelper.free(rs, ps, conn);
}
}
@Test
public void query() {
Connection conn = null;
ResultSet rs = null;
PreparedStatement ps = null;
UserBlob userBlob = new UserBlob();
try {
conn = DbHelper.getConnection();
String sql = "select id,name,image,resume from user_blob where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 1);
rs = ps.executeQuery();
while (rs.next()) {
userBlob.setId(rs.getInt(1));
userBlob.setName(rs.getString(2));
userBlob.setImage(rs.getBlob(3));
userBlob.setResume(rs.getClob(4));
}
} catch (Exception e) {
// TODO: handle exception
}
Clob clob = userBlob.getResume();
Reader reader = null;
System.out.println("Dddd");
try {
reader = clob.getCharacterStream();
BufferedReader br = new BufferedReader(reader);
String s = null;
while ((s = br.readLine()) != null) {
System.out.println(s);
}
} catch (Exception e) {
// TODO Auto-generated catch block
if (e instanceof IOException) {
System.out.println("流转化错误");
}
System.out.println("数据库读取错误");
e.printStackTrace();
} finally {
DbHelper.free(rs, ps, conn);
}
// Blob blob = userBlob.getImage();
// InputStream in;
// try {
// in = blob.getBinaryStream();
// int b = 0;
// while ((b = in.read()) != -1) {
// System.out.print((char) b);
// }
// } catch (Exception e) {
// // TODO Auto-generated catch block
// if (e instanceof SQLException) {
// System.out.println("数据库操作错误");
// } else {
// System.out.println("读取文件错误");
// }
// e.printStackTrace();
// }
}
}
但是这里还有一个问题,这里的主键是自增长的,也就是说insert into的时候本是不需要指定id的,如何使得操作CLOB和BLOB时也不需要插入ID呢,下次再讨论这个问题。
create table user_blob(
id number(10),
name varchar2(20),
image Blob,
resume Clob,
primary key(id)
);
create sequence blob_seq
minvalue 1 maxvalue 99999
start with 1
increment by 1
nocache
nocycle