JDBC+Hibernate将Blob数据写入Oracle

2010-08-28 10:44:58来源:西部e网作者:

   
    Oracle的Blob字段比较特殊,他比long字段的性能要好很多,可以用来保存例如图片之类的二进制数据。

  写入Blob字段和写入其它类型字段的方式非常不同,因为Blob自身有一个cursor,你必须使用cursor对blob进行操作,因而你在写入Blob之前,必须获得cursor才能进行写入,那么如何获得Blob的cursor呢?

  这需要你先插入一个empty的blob,这将创建一个blob的cursor,然后你再把这个empty的blob的cursor用select查询出来,这样通过两步操作,你就获得了blob的cursor,可以真正的写入blob数据了。

  看下面的JDBC的demo,把oraclejdbc.jar这个二进制文件写入数据库表javatest的content字段(这是一个blob型字段)

import java.sql.*;
import java.io.*;
import oracle.sql.*;
public class WriteBlob {

public static void main(String[] args) {

 try {
  DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
  Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","fankai","fankai");
  conn.setAutoCommit(false);

  BLOB blob = null;

  PreparedStatement pstmt = conn.prepareStatement("insert into javatest(name,content) values(?,empty_blob())");
  pstmt.setString(1,"fankai");
  pstmt.executeUpdate();
  pstmt.close();

  pstmt = conn.prepareStatement("select content from javatest where name= ? for update");
  pstmt.setString(1,"fankai");
  ResultSet rset = pstmt.executeQuery();
  if (rset.next()) blob = (BLOB) rset.getBlob(1);

  String fileName = "oraclejdbc.jar";
  File f = new File(fileName);
  FileInputStream fin = new FileInputStream(f);
  System.out.println("file size = " + fin.available());

  pstmt = conn.prepareStatement("update javatest set content=? where name=?");

  OutputStream out = blob.getBinaryOutputStream();

  int count = -1, total = 0;
  byte[] data = new byte[(int)fin.available()];
  fin.read(data);
  out.write(data);
  /*
  byte[] data = new byte[blob.getBufferSize()]; 另一种实现方法,节省内存
  while ((count = fin.read(data)) != -1) {
   total += count;
   out.write(data, 0, count);
  }
  */

  fin.close();
  out.close();

  pstmt.setBlob(1,blob);
  pstmt.setString(2,"fankai");

  pstmt.executeUpdate();
  pstmt.close();

  conn.commit();
  conn.close();
 } catch (SQLException e) {
   System.err.println(e.getMessage());
  e.printStackTrace();
 } catch (IOException e) {
  System.err.println(e.getMessage());
 }
}

}

  仔细看上例,分三步:

  1、插入空blob

into javatest(name,content) values(?,empty_blob());

  2、获得blob的cursor

select content from javatest where name= ? for update;

  注意!!!必须加for update,这将锁定该行,直至该行被修改完毕,保证不产生并发冲突。

  3、update javatest set content=? where name=

  用cursor往数据库写数据

  这里面还有一点要提醒大家:

  JDK1.3带的JDBC2.0规范是不完善的,只有读Blob的接口,而没有写Blob的接口,JDK1.4带的JDBC3.0加入了写Blob的接口。你可以使用JDBC3.0的接口,也可以直接使用Oracle的JDBC的API,我在上例中使用了Oracle的JDBC的API。

  另外要注意的是:

java.sql.Blob

oracle.sql.BLOB

  注意看blob的大小写,是不一样的。写程序的时候不要搞混了。

  下面看看用Hibernate怎么写,原理是一样的,也要分三步,但是代码简单很多

  这是Cat对象定义

package com.fankai;

import java.sql.Blob;

public class Cat {
 private String id;
 private String name;
 private char sex;
 private float weight;
 private Blob image;
 public Cat() { }

 public String getId() { return id; }
 public void setId(String id) { this.id = id; }

 public String getName() { return name; }
 public void setName(String name) { this.name = name; }

 public char getSex() { return sex; }
 public void setSex(char sex) { this.sex = sex; }

 public float getWeight() { return weight; }
 public void setWeight(float weight) { this.weight = weight; }

 public Blob getImage() { return image; }
 public void setImage(Blob image) { this.image = image;}
}

  这是Cat.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class name="com.fankai.Cat" table="cat">
<!--jcs-cache usage="read-only"/-->
<id name="id" unsaved-value="null">
<generator class="uuid.hex"/>
</id>
<property name="name" length="16" not-null="true"/>
<property name="sex" length="1" not-null="true"/>
<property name="weight" />
<property name="image" />
</class>
</hibernate-mapping>

  下面是完整的用Hibernate写入Blob的例子,相比JDBC,已经简单轻松多了,也不用写那些Oracle特殊的sql了:

package com.fankai;

import java.sql.Blob;
import net.sf.hibernate.*;
import oracle.sql.*;
import java.io.*;

public class TestCatHibernate {
 public static void testBlob() {
  Session s = null;
  byte[] buffer = new byte[1];
  buffer[0] = 1;
  try {
   SessionFactory sf = HibernateSessionFactory.getSessionFactory();
   s = sf.openSession();
   Transaction tx = s.beginTransaction();
   Cat c = new Cat();
   c.setName("Robbin");
   c.setImage(Hibernate.createBlob(buffer));
   s.save(c);
   s.flush();
   s.refresh(c, LockMode.UPGRADE);
   BLOB blob = (BLOB) c.getImage();
   OutputStream out = blob.getBinaryOutputStream();
   String fileName = "oraclejdbc.jar";
   File f = new File(fileName);
   FileInputStream fin = new FileInputStream(f);
   int count = -1, total = 0;
   byte[] data = new byte[(int)fin.available()];
   fin.read(data);
   out.write(data);
   fin.close();
   out.close();
   s.flush();
   tx.commit();

  } catch (Exception e) {
   System.out.println(e.getMessage());
  } finally {
   if (s != null)
   try {
    s.close();
   } catch (Exception e) {}
  }
 }
}

赞助商链接:

忐忑
浮夸
说谎
倾世
王妃
煎熬
武装
小三
曾经
素颜
惊叹号
爱很美
春天里
老男孩
皮影戏
走天涯
羽绒服
甩葱歌
套马杆
伤不起
有没有
苦咖啡
追梦人
那些年
大声唱
爱的供养
三寸天堂
荷塘月色
喜欢寂寞
爱情买卖
爱是你我
见或不见
火力全开
一念执着
想你的夜
依然爱你
幸福额度
红尘情歌
明天你好
狼的诱惑
你是我的眼
没那么简单
客官不可以
等你的季节
等不到的爱
美丽与勇敢
我的好兄弟
我们的歌谣
如果爱忘了
梦中的额吉
男人帮片尾曲
最重要的决定
不分手的恋爱
魔鬼中的天使
裸婚时代插曲
当我唱起这首歌
全世界宣布爱你
请安静的忘记我
亲爱的你在哪里
天龙八部之宿敌
爱情睡醒了主题曲
漂亮的姑娘就要嫁人啦
最接近天堂的地方
我爱你胜过你爱我
下辈子做你的女人