`
fw2003
  • 浏览: 80179 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

利用ORACLE JAVA存储过程实现BLOB图片导出

阅读更多

  前几天有朋友让解决个问题:一个XX收单系统,需要的交易情况统计来自另外一套系统,以图片方式进行存储和导出查看.图

 

片以BLOB类型直接存在数据库中.本来以为就是个JAVA操作LOB的问题,但是因为是2次开发,所以必须遵循以前的规定,即所

 

有业务由存储过程实现.他们的选择是用DBMS_LOB和UTL_FILE包,导入图片到数据库没问题,但是在导出时始终不能正确

 

显示,发现导出后文件的大小与导入的图片不一致.

 

其实这又是9i的一个老问题了(为什么我又要说又呢),在Oracle DBA Tips Corner 中说明如下:

It should be noted that in Oracle9i this PL/SQL procedure does not work with all binary files. This is due to Oracle bug (BUG#: 2883782). The PL/SQL procedure that I use to write binary (raw) data out is UTL_FILE.PUT_RAW. This procedure, along with UTL_FILE.GET_RAW, was introduced in Oracle 9i Release 2 as previous versions of UTL_FILE only worked with TEXT files.

In Oracle9i there is currently a restriction of a maximum of 32k that can be written with PUT_RAW unless you insert new line characters in between the data. In Oracle10g there is a new binary mode. When files are opened with this mode, "wb", any amount of raw data can be written without the need for new lines. In short, this is a bug that can bite you if your binary files do not have a new line character within the RAW data in your MAX_LINESIZE buffer. If you do get bit by this bug in Oracle9i, there is no solution that I have found other than writing it in Java.

When I originally started writing and testing the procedure, I was using a fairly small image file (~ 1KB). This worked fine. I later tested a large PDF file (~ 3MB) and it failed (after writing only a small portion of the file) with the following exception:

BEGIN Write_BLOB_To_File; END;
*
ERROR at line 1:
ORA-29285: file write error
ORA-06512: at "SYS.UTL_FILE", line 18
ORA-06512: at "SYS.UTL_FILE", line 1007
ORA-06512: at "SCOTT.WRITE_BLOB_TO_FILE", line 74
ORA-06512: at line 1

Again, using the new binary write mode in Oracle10g when opening binary files should fix this.

 

大意如下:fopen如果用w模式打开,put_raw会自动加回车,哪怕只写一个字符,系统都会把换行符0A转换为0D0A,因为windows是以0D0A为换行符的,也就是说会自动加回车.而在10g中用wb模式打开,是以二进制方式打开,这种方式不会进行”回车符”和”换行符”的转换.也就是说,在9i中,读写2进制文件存在着问题....

 

  很可惜的是:

   1.不可能因为这1个功能就进行数据库地升级,9i也确实是一个BUG满天飞的版本......

   2.由于是2次开发,限制使用存储过程实现,因此无法使用纯JDBC或者spring的OracleLobHandler

 

  考虑了下,我的解决方案如下:

  1.利用一些外部工具,比如lobs_win32.exe(http://www.dbatools.net/software/lobs.zip)实现LOB操作,操作简单,但是不利于与当前项目集成,并且也有基于OCI方式的限制

  2.实际上PL/SQL对IO操作的支持并不好(9i还有个版本会因为参数utl_file_dir设置无效而导致pl/sql无法访问文件系统),而JAVA的IO操作则丰富得多.那么,我们为何不取长补短呢?也就是编写JAVA存储过程,利用简单易用的IO操作来代替PL/SQL中的程序包.

 

=====================我是分割线========================

 

  首先创建测试表,触发器以及对应的DIR:

CREATE TABLE IMAGE_LOB 
(I_ID NUMBER PRIMARY KEY NOT NULL,
I_IMG BLOB NOT NULL);

CREATE OR REPLACE TRIGGER tri_img
BEFORE INSERT ON fw.image_lob
FOR EACH ROW
BEGIN
  SELECT fw.se_test.NEXTVAL INTO :NEW.I_ID FROM dual;
END;

CREATE OR REPLACE DIRECTORY DIR_IMAGES AS 'C:\picture';

 

  接下来编写导入图片的过程:

CREATE OR REPLACE PROCEDURE P_IMG_INSERT (v_filename VARCHAR2)
IS
  v_bfile BFILE;--文件指针
  v_blob BLOB;
  DIR CONSTANT VARCHAR2(20) := 'DIR_IMAGES';--文件存放DIRECTORY
BEGIN
  /*通过empty_blob()函数将类型为blob的列初始化为空以便以后填充*/
  INSERT INTO fw.image_lob (I_IMG)
  VALUES (EMPTY_BLOB ()) RETURN I_IMG INTO v_blob;

  v_bfile:= BFILENAME (DIR, v_filename);--获得定位器指向的目录和文件
  IF (dbms_lob.fileexists(v_bfile)!=0) THEN --如果文件定位器指向的文件存在
    dbms_lob.fileopen(v_bfile,dbms_lob.file_readonly); --打开目标文件

    /*将文件字数据加载到指定的LOB类型变量*/
    dbms_lob.loadfromfile(v_blob,v_bfile,dbms_lob.getlength(v_bfile));

    dbms_lob.fileclose(v_bfile);--关闭文件
    COMMIT;
    dbms_output.put_line('已经从'||DIR||'目录中读取了图片'||v_filename||'向表中插入');

  ELSE--如果文件定位器指向的文件不存在
    dbms_output.put_line('文件没找到');
  END IF;
  EXCEPTION WHEN OTHERS THEN
  dbms_output.put_line(SQLERRM);
END;

 

  测试插入:

SQL> set serveroutput on
SQL> exec fw.p_img_insert(v_filename => '1.JPG');

已经从DIR_IMAGES目录中读取了图片1.JPG向表中插入

PL/SQL procedure successfully completed

 

  现在表格中数据如下:

SQL> select * from fw.image_lob;

      I_ID I_IMG
---------- -----
        21 <BLOB

  

 

  接下来是重点,加载并编译AVA程序,很简单地IO操作:

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "sp_exp_blob" AS
package util;

import java.io.FileOutputStream;
import java.io.OutputStream;

import oracle.sql.BLOB;

public class OracleBlobUtil {
	
		public static void exp(BLOB blob,String expDir) throws Exception{
		    byte[] bt = blob.getBytes(1, (int)blob.length());
		    OutputStream os = new FileOutputStream(expDir);
		    os.write(bt);
		    os.flush();
		    os.close();
	}
}

 

  创建对应的过程:

 

CREATE OR REPLACE PROCEDURE p_exp_blob(v_blob BLOB,v_exp_dir VARCHAR2)
AS LANGUAGE JAVA NAME 'util.OracleBlobUtil.exp(oracle.sql.BLOB,java.lang.String)';

 

  测试导出功能:

DECLARE
  v_blob fw.image_lob.i_img%TYPE;
BEGIN
  SELECT i_img INTO v_blob FROM fw.image_lob WHERE i_id=21;
  dbms_java.grant_permission( 'FW', 'SYS:java.io.FilePermission', 'c:/picture/1_exp.jpg', 'write' );
  fw.p_exp_blob(v_blob => v_blob,v_exp_dir => 'c:/picture/1_exp.jpg');
END;

 

   成功的话将在c:/picture下看到1_exp.jpg.

   注意兰色这行代码,是设置对文件的写的权限,如果没有的话,会出现java.security.AccessControlException: the Permission.....,可以参看老外的这篇帖子http://cn.forums.oracle.com/forums/thread.jspa?threadID=832298&tstart=0&messageID=3149561#3149561.更进一步的信息,可以查询OracleJava安全方面的文档.

  

  当然也可以单独地对用户进行权限授予

  

 

SQL> connect sys/is311027@feng as sysdba;
Connected to Oracle9i Enterprise Edition Release 9.2.0.1.0 
Connected as SYS

SQL> call dbms_java.grant_permission( 'FW', 'SYS:java.io.FilePermission', 'c:/picture/1_exp.jpg', 'write' );

Method called

 

 

  最后总结如下,利用从8i开始就引入的JVM,我们可以利用JAVA和PL/SQL进行互补.利用JAVA的各种优点来扩展数据库应用

 

的功能,并且充分利用高效的内存回收技术和线程管理方面的能力,而不再是局限于PL/SQL.而正如本文中的例子,PL/SQL

 

Java 可以在同一个应用中和谐共处,2者是可以共存的.同时使用两个世界最好的方法,让我们能够开发出更好的数据库应

 

用.最后再说句,9i真龌龊....

2
0
分享到:
评论
2 楼 fw2003 2010-04-26  
jw2007 写道
我想问问,大型系统中的图片,都是保存在数据库里面吗?

163相册、QQ相册都是保存在数据库里面吗?

像163相册、QQ相册之类一般是不提供外链接这样可以提高163、QQ用户的访问相册速度。

如果是像Yahoo flickr这种全球提供外链接的图片的服务器,是如何实现的?

也是保存在数据库里面吗?把图片保存在数据库里面是最佳实践吗?


将整个文件保存在数据库中肯定是有特殊需求的
比如只有本地地操作 或者是遗留系统地2次开发 比如对被上传的文件的访问需要一定的权限等等 这时就不能简单地将图片放在服务器端的某个目录下

而一般基于互联网的应用为了伸缩性考虑都是仅仅在数据库中只保存名字或路径
不对外提供链接是为了减少不必要地请求连接数

就拿一个普通的大型网站来说 首先APP SERVER和DB SERVER应该分开部署 其次图片服务器应该独立出来 静态请求应该交给类似apache的WEB SERVER处理  然后做集群/CACHE等等 这些不是1句话说得清楚的
1 楼 jw2007 2010-04-26  
我想问问,大型系统中的图片,都是保存在数据库里面吗?

163相册、QQ相册都是保存在数据库里面吗?

像163相册、QQ相册之类一般是不提供外链接这样可以提高163、QQ用户的访问相册速度。

如果是像Yahoo flickr这种全球提供外链接的图片的服务器,是如何实现的?

也是保存在数据库里面吗?把图片保存在数据库里面是最佳实践吗?

相关推荐

    批量导出ORACLE数据库BLOB字段生成图片

    Oracle数据库在存储大对象(BLOB)数据时,提供了高效且灵活的方式,使得二进制数据如图片、文档等能够安全地保存在数据库中。批量导出Oracle数据库中的BLOB字段生成图片,是一项常见的需求,尤其对于那些需要将...

    批量导出ORACLE数据库BLOB字段生成文件

    例如,假设你有一个名为`photos`的表,其中`filename`列存储文件名,`image_data`列存储BLOB数据。 以下是一个示例PL/SQL代码段,用于遍历`photos`表,读取BLOB数据,并将其保存为本地文件: ```sql DECLARE v_...

    Oracle导出Clob,Blob工具

    Oracle数据库在处理大对象(LOB)类型,如Clob(Character Large Object)和Blob(Binary Large Object)时,有时需要专门的工具来进行高效且安全的数据导出。这些字段通常存储大量的文本或二进制数据,比如长篇文档...

    oracle中的BLOB(照片)转换到mysql中

    Oracle数据库系统支持多种复杂的数据类型,其中包括BLOB(Binary Large Object),用于存储非结构化的大数据,如图片、音频或视频文件。而MySQL同样提供了BLOB类型,用于相似的用途。本篇将详细讲解如何在Oracle与...

    Oracle导出图片源代码

    "Oracle导出图片源代码"是针对这个需求编写的一段程序,它可以有效地从Oracle数据库中导出存储在BLOB字段中的图片。 首先,我们要理解Oracle数据库中如何存储和访问图片。BLOB字段用于存储大量的二进制数据,包括...

    照片批量导入导出

    在本场景中,"照片"以BLOB类型存储在Oracle数据库中,用于存储和管理大量的图片资源。 2. **BLOB数据类型**:BLOB(Binary Large Object)是数据库系统中用于存储大量非结构化数据的类型,如照片、音频或视频文件。...

    sql server中的image类型的数据导出到oracle的clob字段中

    我们使用了 Java 语言和 JDBC 驱动程序来实现数据的导出,并将 Image 类型数据写到文件中,然后将文件中的数据读取出来,并将其设置到 Oracle 的 CLOB 字段中。这种方法可以帮助我们实现不同数据库管理系统之间的...

    Oracle bolb 文件导出

    Oracle数据库中的BLOB(Binary Large Object)类型是用来存储大量二进制数据的,例如图片、文档、音频或视频文件等。在处理大量这样的数据时,高效地导出BLOB字段到本地文件系统变得至关重要。本篇文章将深入探讨...

    图片导出到文件夹

    通过以上分析,我们可以看到这段代码实现了一个完整的从Oracle数据库导出图片到文件夹的过程。这对于需要处理大量图片数据的应用场景来说非常实用。此外,还可以根据实际需求对代码进行相应的调整和优化,比如增加...

    ORACLE导出到EXCEL

    本文将详细介绍如何利用Java编程语言,结合JXL库来实现这一过程,特别是处理BLOB类型的文件。 首先,理解BLOB类型。BLOB(Binary Large Object)在Oracle数据库中用于存储二进制大数据,如图片、文档或音频文件。在...

    Oracle导入导出图片及Excel(标注:没有源代码!)

    可以编写PL/SQL过程或者使用Java、C#等编程语言,调用Oracle的JDBC或ODBC驱动,获取BLOB数据并保存为图片文件。 4. **Excel数据交互**:在Oracle与Excel之间进行数据交换,通常会用到API库,如Java的Apache POI(在...

    Blob数据下载到本地

    Blob(Binary Large Object)在数据库中用于存储二进制大对象,如图片、音频或视频文件等。在Oracle数据库中,Blob类型常用来保存大量的非结构化数据。本篇文章将详细讲解如何从Oracle数据库中下载Blob数据并将其...

    OracleBlobToJPG

    Oracle数据库是一种广泛应用的关系型数据库管理系统,它支持多种数据类型,包括Blob(Binary Large Object)类型,用于存储大块二进制数据,如图片、视频或文档。本篇文章将详细介绍如何将Oracle数据库中的Blob类型...

    load blob clob

    Blob主要用于存储二进制数据,如图片、视频或文档,而Clob则用于存储字符型的大数据,如长篇文本或XML文件。本篇文章将围绕"load blob clob"这一主题,结合anysql免费工具合集,详细介绍如何在Oracle中操作Blob和...

    BLOB数据存取

    存储BLOB数据时,你可以使用`_Parameter`对象,将其`Type`属性设置为`adLongVarBinary`,然后将二进制数据传递给`Value`属性。例如: ```cpp _CommandPtr cmd; cmd.CreateInstance(__uuidof(Command)); cmd-&gt;...

    ORACLE驱动程序JAR包下载 解决编辑器内WORD特殊格式粘贴问题

    3. **利用Oracle的BLOB和CLOB字段**:对于图片和长文本,可以考虑存储在BLOB(Binary Large Object)和CLOB(Character Large Object)字段中。这样,数据的原始格式可以得到保留。 4. **第三方库支持**:使用专门...

    PRM-DUL Oracle(数据库恢复工具) v4.1.zip

    其导出的数据既可导出为sqlldr导入数据文件,也可通过PRM-DUL的Data Bridge功能直接导出并插入到指定新库中,实现不落地恢复。 PRM-DUL Oracle数据库恢复工具功能 》》可以在不需要运行Oracle数据库的情况下直接...

    从oracle生成表的数据字典方法

    本篇文章将介绍如何从Oracle数据库中利用COMMENT生成Excel格式的数据字典。 #### 一、Oracle数据库的数据字典简介 Oracle数据库提供了丰富的数据字典视图来存储数据库对象的信息,这些视图分为不同的类别:`ALL_`...

    数 据 库 笔 记 oracle

    7. **存储过程和函数**:存储过程和函数是预编译的SQL代码块,可提高代码复用性和安全性。它们允许在数据库层面进行复杂逻辑处理。 8. **触发器**:触发器是一种数据库对象,当满足特定事件(如INSERT、UPDATE或...

Global site tag (gtag.js) - Google Analytics