Insert BLOB && CLOB from PL/SQL and JDBC
For PL/SQL
1)Create Directory Where BLOB resides.
create or replace directory temp as '/oradata2';
-- if the directory name you created not qoted, then you can only use upper case to refer it.
-- create or replace directory temp as 'xxxx', the temp directory can only be refered as TEMP.
-- create or replace directory "temp" as 'xxxx', the temp directory can only be refered as temp.
2)Grant read permission to the user who work with this directory.
grant read on directory temp to test;
3)Create the Table which holds lob object.
-- the storage table for the image file
CREATE TABLE pdm (
dname VARCHAR2(30), -- directory name
sname VARCHAR2(30), -- subdirectory name
fname VARCHAR2(30), -- file name
iblob BLOB); -- image file
4)Create the procedure that insert BLOB objects.
-- create the procedure to load the file
CREATE OR REPLACE PROCEDURE load_file (
pdname VARCHAR2,
psname VARCHAR2,
pfname VARCHAR2)
IS
src_file BFILE;
dst_file BLOB;
lgh_file BINARY_INTEGER;
BEGIN
src_file := bfilename('TEMP', pfname);
-- insert a NULL record to lock
INSERT INTO pdm (dname, sname, fname, iblob) VALUES (pdname, psname, pfname, EMPTY_BLOB()) RETURNING iblob INTO dst_file;
-- lock record
SELECT iblob INTO dst_file FROM pdm
WHERE dname = pdname
AND sname = psname
AND fname = pfname
FOR UPDATE;
-- open the file
dbms_lob.fileopen(src_file, dbms_lob.file_readonly);
-- determine length
lgh_file := dbms_lob.getlength(src_file);
-- read the file
dbms_lob.loadfromfile(dst_file, src_file, lgh_file);
-- update the blob field, this step can be ignored as lob type is using pointer , privious step we have changed the content of the lob.
UPDATE pdm SET iblob = dst_file WHERE dname = pdname AND sname = psname AND fname = pfname;
-- close file
dbms_lob.fileclose(src_file);
END load_file;
/
5)Execute the Procedure.
SQL> exec load_file('TEMP','This is Image','tritha7.png');
PL/SQL procedure successfully completed.
6) From OS see the BLOB size.
SQL> !ls -l /oradata2/tritha7.png
-rwxr-xr-x 1 oracle oinstall 21150 Jun 9 01:55 /oradata2/tritha7.png
7)From Oracle Determine Blob size.
1 declare
2 a blob;
3 begin
4 select iblob into a from pdm;
5 dbms_output.put_line(dbms_lob.getlength(a));
6* end;
SQL> /
PL/SQL procedure successfully completed.
SQL> set serverout on
SQL> /
21150
For JDBC:
java.sql.PreparedStatement pstmt = null;
ResultSet rs = null;
String query = "";
conn.setAutoCommit(false);
query = "insert into clobtest_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_table where 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字段中了。如:
SQL> select dbms_lob.getlength(picstr) from clobtest_table;
(3)对数据库clob型执行读取操作
*************************************************
读取相对插入就很简单了。基本步骤和一半的取数据库数据没有太大的差别。
String description = ""
query = "select picstr from clobtest_table where 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());
System.out.println("======字符串形式 "+description);
}
}
补充一个队LOB进行深度COPY的例子
create or replace
procedure NDSSP_backup_fund (fund_id_in in varchar2 ,selector_in in varchar2,
time_in in timestamp,blob_in in BLOB)
is
key number;
blob_tmp blob;
begin
delete from fund_backup bf where bf.selector = selector_in and bf.fund_id = fund_id_in;
select fund_backup_seq.nextval into key from dual;
insert into fund_backup values(key,selector_in,fund_id_in,empty_blob(),time_in);
select content into blob_tmp from fund_backup where id = key for update; -- we can ignore this as the insert statement already hold the X row lock.
dbms_lob.copy(blob_tmp, blob_in, dbms_lob.getLength(blob_in));
end NDSSP_backup_fund;
11G 的insert into xxx select 也支持LOB字段复制了. 下面是个例子
SQL> select * from test.blobtest;
ID CONTENTS
---------- ------------------------------------------------------------
1 504B0304140002000800D380F8446CFABED08E36030051E7220012000000
2 504B0304140002000800D380F8446CFABED08E36030051E7220012000000
SQL> conn test/test
已连接。
SQL> create table test2(id int primary key, aa blob);
表已创建。
SQL> insert into test2 select * from blobtest;
已创建2行。
SQL> select * from test2;
ID AA
---------- ------------------------------------------------------------
1 504B0304140002000800D380F8446CFABED08E36030051E7220012000000
2 504B0304140002000800D380F8446CFABED08E36030051E7220012000000
dbms_lob.LOADBLOBFROMFILE && dbms_lob.loadclobfromfile 的诡异用法
create or replace dir DUMP_DIR as 'd:\myzip'
grant read,write on directory DUMP_DIR to test;
create table blobtest (id int primary key,contents blob);
declare
l_blob blob;
l_bfile bfile;
DEST_OFFSET NUMBER;
SRC_OFFSET NUMBER;
begin
DEST_OFFSET:=1;
SRC_OFFSET:=1;
insert into test.BLOBTEST values (4, empty_blob()) returning contents into l_blob;
l_bfile := bfilename('DUMP_DIR', 'gpdb_ora_16750.zip');
dbms_lob.fileopen(l_bfile);
dbms_lob.LOADBLOBFROMFILE(l_blob,l_bfile, dbms_lob.getlength(l_bfile),DEST_OFFSET,SRC_OFFSET); -- 这里DEST_OFFSET 和 SRC_OFFSET 参数不能少,1表示从头开始.
dbms_lob.fileclose(l_bfile);
COMMIT;
end;
/
create table demo( id int primary key,bb clob);
declare
l_clob clob;
l_bfile bfile;
DEST_OFFSET NUMBER;
SRC_OFFSET NUMBER;
csid NUMBER;
lang_context NUMBER;
warning NUMBER;
begin
DEST_OFFSET:=1;
SRC_OFFSET:=1;
csid :=0;
lang_context :=0;
warning :=0;
insert into demo values (1, empty_clob()) returning bb into l_clob;
l_bfile := bfilename('DUMP_DIR', 'aa.txt');
dbms_lob.fileopen(l_bfile);
dbms_lob.loadclobfromfile(l_clob, l_bfile,DBMS_LOB.LOBMAXSIZE,DEST_OFFSET,SRC_OFFSET,csid,lang_context,warning);
dbms_lob.fileclose(l_bfile);
COMMIT;
end;
各个参数的解释如下:
amount | DBMS_LOB.LOBMAXSIZE (IN) | Load the entire file |
dest_offset | 1 (IN) | start from the beginning |
src_offset | 1 (IN) | start from the beginning |
csid | 0 (IN) | default csid, use destination csid |
lang_context | 0 (IN) | default language context |
warning | 0 (OUT) | no warning message, everything is ok |
补充
在对LOB字段插入数据的时候,如果是CLOB,可以直接写字符串(前提是小于4000,字符串直接量最大4000字符).
如果是BLOB,可以用utl_raw.cast_to_raw,下面是一个例子。
insert into GPCORRHISTATT(id,corrhist_id,contents) values(2,2,utl_raw.cast_to_raw('aaaaaaaaaaddcddd'));
BLOB/CLOB 互相转换
CREATE OR REPLACE FUNCTION clob_to_blob(b IN CLOB default empty_clob()) RETURN BLOB
AS
res BLOB;
b_len number := dbms_lob.getlength(b) ;
dest_offset1 NUMBER := 1;
src_offset1 NUMBER := 1;
amount_c INTEGER := DBMS_LOB.lobmaxsize;
blob_csid NUMBER := DBMS_LOB.default_csid;
lang_ctx INTEGER := DBMS_LOB.default_lang_ctx;
warning INTEGER;
BEGIN
if b_len > 0 then
DBMS_LOB.createtemporary (res, TRUE);
DBMS_LOB.OPEN (res, DBMS_LOB.lob_readwrite);
DBMS_LOB.convertToBlob (res,
b,
amount_c,
dest_offset1,
src_offset1,
blob_csid,
lang_ctx,
warning
);
else
select empty_blob() into res from dual ;
end if ;
RETURN res;
END clob_to_blob;
CREATE OR REPLACE FUNCTION blob_to_clob (blob_in IN BLOB) RETURN CLOB
AS
v_clob CLOB;
v_varchar VARCHAR2(32767);
v_start PLS_INTEGER := 1;
v_buffer PLS_INTEGER := 32767;
tmp_num number;
BEGIN
DBMS_LOB.CREATETEMPORARY(v_clob, TRUE);
tmp_num := CEIL(DBMS_LOB.GETLENGTH(blob_in) / v_buffer);
if tmp_num > 0 then
FOR i IN 1..tmp_num
LOOP
v_varchar := UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(blob_in, v_buffer, v_start));
DBMS_LOB.WRITEAPPEND(v_clob, LENGTH(v_varchar), v_varchar);
v_start := v_start + v_buffer;
END LOOP;
end if;
RETURN v_clob;
END blob_to_clob;