原来做数据库对图片的存储都是直接存储图片在服务器中的路径,但是今天老大要求需要存储图片进去,没办法,老老实实的存图片。下面我就这个过程写下一个测试的实例。
首先,我在数据库中建了一个表,如下:
-- Create table
create table TESTCLOB
(
cid NUMBER(4),
pathname VARCHAR2(100),
picture CLOB
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
就三个字段,cid应该是主键,唯一标示,因为这里只是测试用,所以就没有声明为主键。pathname,当然是所需要存储的对象在服务器中的地址,我这里以图片为例,当然就是图片的地址。picture,放图片的字段,是个clob(大对象)类型。下面的是表空间,当然你可以不写,oracle会给你一个默认的表空间。
下面就是java代码了。
在myeclipse中建一个类,文件名为TestClob.java,此文件中我放了两个类,一个public的,一个默认的。
public的是用来对数据库进行插入操作的。而另一个则是管理数据库连接的DBManager类。
首先来看DBManager类:
class DbManager{
Connection conn = null;
PreparedStatement stmt = null;
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
//获得数据库连接的方法
public Connection getConnection(){
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, "scott", "tiger");
//stmt=conn.prepareStatement(sql);
System.out.println("获得连接成功!");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//获得PreparedStatement的方法
public PreparedStatement getstmt(String sql){
try {
stmt=conn.prepareStatement(sql);
System.out.println("获得stmt对象!");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stmt;
}
}
写完可以在public类中建个DBManager对象调用这两个方法,看看连接是否成功。
下面就来看看public类:
类名当然就是文件名了,public class TestClob,显然,就是TestClob了。
下面我们来看其中的方法:
首先是主方法:
public static void main(String[] args) {
String path="D:\\temp\\a.jpg";
TestClob tc=new TestClob();
tc.add(path);
}
里面创建了一个TestClob的对象,然后用此对象调用了本类的add方法(下面将会给出),传入了图片的路径。
下面就是重点了,此方法将会把对应路径的图片插入到数据库中去:
public void add(String path){
Connection conn = null;
PreparedStatement stmt = null;
//首先让数据库中需要插入的此条记录的clob对象初始化,用empty_clob()方法
String sql ="insert into testclob(cid,pathname,picture) values(?,?,empty_clob())";
//这里创建DBManager类的对象db,获得连接。创建db对象你可以自己new,全局的还是局部的,由你决定,当然我这里用的全局的
conn=db.getConnection();
//设置提交方式,这里不让数据库默认提交
//如果你的程序抛出了java.sql.SQLException: ORA-01002: 提取违反顺序 这种异常,那么你就该考虑加上这句话了
//conn.setAutoCommit(false);
stmt=db.getstmt(sql);
try {
//设置参数值
stmt.setInt(1, 1);
stmt.setString(2, path);
//执行sql语句,我这里是PreparedStatement所以就直接executeUpdate()了,如果你的是Statement对象的话,就应该是executeUpdate(sql)方法了
stmt.executeUpdate();
System.out.println(path);
//下面几是插入clob对象的图片了
String query="select picture from testclob where pathname=? for update";
stmt=db.getstmt(query);
stmt.setString(1, path);
//得到查询结果集,很明显,这个结果集应该只有一条记录的
ResultSet rs =stmt.executeQuery();
//使结果集指针向下移动一位,在java中查询出来的结果集的指针当前指的都是最上面的没有数据的位置,向下移动一位才是第一条数据
rs.next();
//使用CLOB类型接收从结果集中查询出来的大对象字段
CLOB myClob=((OracleResultSet)rs).getCLOB("picture");
//获得对象的大小
int chunkSize = myClob.getChunkSize();
//为此对象创建缓冲
char [] textBuffer = new char[chunkSize];
//根据图片路径穿件文件
File myFile = new File(path);
FileInputStream myFileInputStream=null;
InputStreamReader myReader=null;
BufferedReader myBufferedReader=null;
try {
//获得输入文件流,建立通道
myFileInputStream = new FileInputStream(myFile);
//获得读文件流对象,从通道中读取数据
myReader =new InputStreamReader(myFileInputStream);
//获得缓冲流对象,读取的对象到缓冲流中去,这也是一般的文件操作的步骤,以此可以看出java的层层封装
myBufferedReader = new BufferedReader(myReader);
long position = 1;
int charsRead;
while ((charsRead = myBufferedReader.read(textBuffer)) != -1){
myClob.putChars(position, textBuffer);
position += charsRead;
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
myBufferedReader.close();
myReader.close();
myFileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//做完提交持久化改变
stmt.execute("COMMIT");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
至此这个小例子就完成了。住大家顺利!