【问题标题】:Updating blob shows PL/SQL success but no content change更新 blob 显示 PL/SQL 成功,但没有内容更改
【发布时间】:2017-11-12 10:46:06
【问题描述】:

尝试为多行更新 blob 列中的图片,我收到成功的消息,没有错误,但尚未呈现更改。我重新启动了 Oracle 服务和机器,但仍然没有传播。是的,如图所示,我正在提交,但我只尝试了一个 blob 无济于事。

  • 它是临时的 dest_lob 对象吗? readonly 类型?我必须释放临时 blob 吗?
  • 是否未设置适当的架构?我用架构用户调用它。
  • 以前的 blob 内容是否必须是 NULL? Hamlet.jpg 尝试 (ID = 101) 在 Picture blob 列中维护 NULL
  • 这是否是 Oracle 的缓存问题?我是否必须刷新表空间文件之类的内容?
  • 是多个BEGIN ... END 调用吗?

表格

 SQL > desc Characters;
 Name                  Null?    Type
 ----------------------------------------------------------------
 ID                    NOT NULL NUMBER(5)
 CHARACTER                      VARCHAR2(255 CHAR)
 DESCRIPTION                    VARCHAR2(1000 CHAR)
 SOURCE                         VARCHAR2(255 CHAR)
 QUOTE                          VARCHAR2(1500 CHAR)
 PICTURE                        BLOB
 LINKIMAGE                      VARCHAR2(255 CHAR)

PL-SQL

CREATE OR REPLACE DIRECTORY MY_DIR AS '/path/to/pictures';
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'HenryCorwin.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 44;
  DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
  DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.CLOSE(src_bfile);
  COMMIT;
END;
/
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'Hamlet.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 101;
  DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
  DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.CLOSE(src_bfile);
  COMMIT;
END;
/
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'CGreen.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM  CHARACTERS WHERE ID = 15;
  DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
  DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.CLOSE(src_bfile);
  COMMIT;
END;
/
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'SevenOfNine.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 82;
  DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
  DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.CLOSE(src_bfile);
  COMMIT;
END;
/

sqlplus 命令行调用 (上述脚本)

SQL> @/path/to/script.sql

控制台输出

Directory created.


PL/SQL procedure successfully completed.


PL/SQL procedure successfully completed.


PL/SQL procedure successfully completed.


PL/SQL procedure successfully completed.

SQL Blob 数据检查

SELECT ID FROM Characters
WHERE DBMS_LOB.GETLENGTH(Picture) = 0 OR 
      DBMS_LOB.GETLENGTH(Picture) IS NULL;

输出

    ID
----------
    15
    44
    82
   101

环境

  • Ubuntu 16.04 LTS,64 位
  • Intel Celeron,4 处理器,64-GB HD,2-GB RAM
  • Oracle 11g 速成版:

    SQL > select * from v$version
    
    Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
    PL/SQL Release 11.2.0.2.0 - Production
    CORE    11.2.0.2.0  Production
    TNS for Linux: Version 11.2.0.2.0 - Production
    NLSRTL Version 11.2.0.2.0 - Production
    

【问题讨论】:

  • 尝试INSERT INTO Characters ( ID, Picture ) VALUES ( 44, EMPTY_BLOB() );,然后使用您的匿名 PL/SQL 块。 SQLFIDDLE
  • @MTO 我很欣赏这个建议。但是,我不想追加新行而是更新现有行。您的示例适用于空表。我们可以为UPDATE 设置它吗?或者也许我必须用EMPTY_BLOB 实体和writeappend 更新图片
  • 当您将DBMS_LOB.GETLENGTH (src_bfile) 放入variable 并传递变量时会得到什么。可以试一次吗?
  • @XING - 我试过没有用:dest_length:= DBMS_LOB.GETLENGTH (src_bfile) ... AMOUNT => dest_length.
  • 你所做的是绝对正确的。您需要查看其他地方是否存在问题。

标签: oracle plsql blob


【解决方案1】:

在其他论坛thread 的帮助下,我找到了我的问题。而不是使用以下 LOB 方法:

DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);

只需替换为 FILE 版本并删除 CREATETEMPORARY():

DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);

事后看来,这是有道理的,因为我从文件对象 src_bfile 中读取,而不是实际的 blob 对象。

使用以下更新的 PL/SQL 例程,blob 列成功呈现。

CREATE OR REPLACE DIRECTORY MY_DIR AS '/path/to/pictures';
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'HenryCorwin.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 44 FOR UPDATE;
  DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.FILECLOSE(src_bfile);
  COMMIT;
END;
/
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'CGreen.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM  CHARACTERS WHERE ID = 15 FOR UPDATE;
  DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.FILECLOSE(src_bfile);
  COMMIT;
END;
/
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'SevenOfNine.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 82 FOR UPDATE;
  DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
  DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.FILECLOSE(src_bfile);
  COMMIT;
END;
/

另外,如果 blob 列是 NULL 就像我的 Hamlet.jpg 尝试,上述过程将失败并显示

ORA-06502:PL/SQL:数字或值错误:无效的 LOB 定位器 指定:

ORA-22275 ORA-06512:在“SYS.DBMS_LOB”,第 928 行 ORA-06512: 在第 7 行

要解决此问题,请先使用 EMPTY_BLOB() 进行更新,然后再使用预期对象更新 blob。

UPDATE CHARACTERS SET Picture = EMPTY_BLOB() WHERE ID = 101;
DECLARE
  src_bfile BFILE := BFILENAME('MY_DIR', 'Hamlet.jpg');
  dest_blob BLOB;
BEGIN
  SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 101 FOR UPDATE;
  DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
  DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                         SRC_LOB  => src_bfile,
                         AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
  DBMS_LOB.FILECLOSE(src_bfile);
  COMMIT;
END;
/

成功的消息渲染和最终的查询返回一个眼睛酸痛的景象:

SQL > SELECT ID FROM Characters WHERE DBMS_LOB.GETLENGTH(Picture) = 0 OR DBMS_LOB.GETLENGTH(Picture) IS NULL;

no rows selected

SQL > SQL> SELECT DBMS_LOB.GETLENGTH(Picture) FROM Characters WHERE ID IN (15, 44, 82, 101);

DBMS_LOB.GETLENGTH(PICTURE)
---------------------------
                     365256
                     412300
                     381586
                     404241

【讨论】:

    【解决方案2】:

    我建议你做一个dbms_lob.erase,这似乎是必要的:

    SELECT PICTURE INTO dest_blob FROM CHARACTERS WHERE ID = 15
       FOR UPDATE;
    dest_length := DBMS_LOB.GETLENGTH(dest_blob);
    IF dest_length <> 0 THEN
      DBMS_LOB.ERASE(dest_blob,dest_length,1);
    END IF;
    
    -- then do as you wrote:
    DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
    DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
    DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
                           SRC_LOB  => src_bfile,
                           AMOUNT   => DBMS_LOB.GETLENGTH(src_bfile) );
    DBMS_LOB.CLOSE(src_bfile);
    COMMIT;
    

    希望对你有帮助(从here偷来的)

    【讨论】:

    • 不幸的是,与奇怪的 success 消息完全相同的输出,没有错误但没有更新!
    猜你喜欢
    • 2020-06-11
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    相关资源
    最近更新 更多