【问题标题】:deserialize java object from a blob从 blob 反序列化 java 对象
【发布时间】:2013-01-23 23:24:07
【问题描述】:

首先,我很抱歉,我要问一些愚蠢的问题。我根本不懂java,我不知道我们是否可以问这样的问题。

如果不是 - 删除我的主题。

oracle 中有一个存储 blob 的表。它是二进制的,我可以解码它,输出看起来像这样

¬í sr /com.epam.insure.credentialing.forms.StorageBeanÀÓ ¯w/§ L     variablest Ljava/util/Map;xpsr java.util.HashMapÚÁÃ`Ñ F 
loadFactorI     thresholdxp?@     w      t $_hasCompletedt  t 
$_wf_progresssr java.lang.Integerâ ¤÷‡8 I valuexr java.lang.Number†¬•”à‹  xp   t $_wf_statussq ~    t $_form_instance_idsr java.lang.Long;‹äÌ#ß J valuexq ~          ‹©t $_isVisitedt truet 1sq ~  sq ~ ?@     `w   €   _t  confidential readable infot 1t confidential readable infot $_errorssr java.util.ArrayListxÒ™Ça I sizexp    w   
xt regionIdsq ~       ët 
confidential readable infot t  t $_subbean_errorssq ~     w   
xt regiont  SOUTHWESTt idt  t codet  t reqTypeNamet 
confidential readable infot t confidential readable infot tint  t $_hasCompletedt falset comRequiredt  t 
lineImpactq ~ t prChiropractorsq ~ t fromTypeReqt not zipt 342t changeToTypeReq6t confidential readable infot t 
prPodiatristsq ~ t 
$_isValidatedt truet $_hasErrorsq ~ -t EVPapprovalsq ~  sq ~ ?@     w   Approvedq ~ Ct 
NEGOTIATORq ~ Et 
Negotiatort datet 
03/31/2006q ~ It confidential readable infot q ~ \xt updateRequiredt noq ~ t truet  approverssr .forms.StorageBeanList«WtúœG  xq ~    w   
q ~ Rsq ~  sq ~ ?@     w      t commentst  t decisiont Approvedq ~ Ct RVPq ~ Et RVPt datet 
04/04/2006q ~ It t commentst  t decisiont Approvedq ~ Ct COOq ~ Et COOt datet 
04/14/2006q ~ It ~ †xsq ~  sq ~ ?@     w      t commentsq ~ Pt decisiont Approvedq ~ Ct CEOq ~ Et CEOt d

这是我的问题

    1234563我很绝望) - 唯一插入的是没有引号的“¬í”。此外,我无法选择全部并从 DBMS 输出窗口复制它,再次粘贴的唯一内容是没有引号的“¬í”。似乎这个文本并不存在。有人知道如何将其插入表格吗?
  1. 如果我以正确的方式使用 java,我应该从哪里开始?请原谅这种愚蠢,但我什至不知道如何运行 java 代码。我在网上找到了一些示例代码,但我不知道在哪里粘贴它:)

我在谷歌上搜索了一下,发现我必须在文本编辑器中创建一个 .java 文件然后编译它,这对我来说是真的吗?我想也许那是一些不同的 java 代码,我想也许在我的情况下我必须从 oracle 运行它,因为那是表所在的位置。

我也有表格结构,我附上了一部分。这个 blob 存储一个表。

无论如何,我确信现在很明显我一无所知。如果有人能指出我的某个地方,我将不胜感激。

谢谢

【问题讨论】:

  • 欢迎来到 SO。这看起来确实有点像序列化的 Java 对象。要提取数据,您需要编写一个可以访问类定义的 Java 程序(即com.epam.insure.credentialing.forms.StorageBean 和其他)。向没有 Java 知识的人解释这一点绝对超出了本网站的范围。您可能需要找一个 Java 开发人员来帮助您。如果您无权访问数据中使用的类,您可能会不走运。
  • 我在网上找到了一些代码,我想试试,但我该如何运行呢?我要创建一个 .java 文件并编译它吗?或从蟾蜍运行它?或者这是怎么做的?另外,我认为该类是 Storage Bean,或者那不是类?
  • 您需要编写一个 Java 类并对其进行编译。除了 Java 本身,还有很多东西需要学习,包括如何使用 IDE(Eclipse 或 Netbeans)以及如何使用 JDBC 读取数据库。您无法在屏幕上打印出 blob 并复制/粘贴您已经发现的内容,因为它包含二进制(即不可打印)字符。
  • 知道了,谢谢。我仍然会尝试))))))永远不知道,我可能会让它工作。
  • @JimGarrison 嘿,还有几个问题。我正在研究eclipse和netbeans,但我想首先确保这是可行的。意思是,我是否有足够的信息来实现它,或者是否有一些只有开发人员才有的东西,即使我知道怎么做——我做不到?另外,是否可以使用这个主题来询问我在此过程中会遇到的任何问题?还是我应该为每个问题创建一个新主题?

标签: java oracle oracle11g blob deserialization


【解决方案1】:

我将在某个时候学习在 java 中执行此操作,但由于这很匆忙 - 我决定使用 SQL 从 blob 中提取字段。我把这个放在这里,以防其他人迫切地想要这样做。

这是一个非常丑陋和缓慢的解决方案,但到目前为止我能够获得一些领域。完成后我会更新,说明我是否能够得到所有东西。

这是我正在使用的代码(这仅适用于 1 个字段,但它会给你一个想法)

    DECLARE
     CURSOR c_dts IS
       SELECT Form_ID
         FROM NR_DTS_FORMTABLE
        WHERE   1 = 1
           --AND ROWNUM BETWEEN 501 AND 4500
           AND form_ID > 204815
           --AND ROWNUM < 5000
           AND ROWNUM < 3
           --AND form_id IN (SELECT form_id FROM NR_DTS_BLOB)
           AND Form_Type_ID = 102;
     DTS c_dts%ROWTYPE;
BEGIN
     OPEN c_dts;
     LOOP
       FETCH c_dts INTO DTS;
       EXIT WHEN c_dts%NOTFOUND;
       DECLARE
         v_hold_blob BLOB;
         v_len NUMBER;
         v_raw_chunk RAW(10000);
         v_chr_string VARCHAR2(32767);
         -- v_chr_string CLOB;
         v_position NUMBER;
         c_chunk_len NUMBER := 1;
         Form_ID NUMBER;
       BEGIN
         SELECT form_content
           INTO v_hold_blob
           FROM NR_DTS_FORMTABLE
          WHERE Form_ID = DTS.Form_ID;
         v_len := DBMS_LOB.getlength(v_hold_blob);
         v_position := 1;
         WHILE (v_position <= LEAST(v_len, 32767)) LOOP
              v_raw_chunk := DBMS_LOB.SUBSTR(v_hold_blob, c_chunk_len, v_position);
              v_chr_string := v_chr_string || CHR(hex_to_decimal(RAWTOHEX(v_raw_chunk)));
              v_position := v_position + c_chunk_len;
         END LOOP;

         --insert into table
         INSERT INTO NR_DTS_BLOBFIELDS_VARCHAR(formid
                               ,regionId)
              SELECT DTS.Form_ID
                 ,SUBSTR(v_chr_string
                     ,INSTR(v_chr_string, 'regionIdt') + LENGTH('regionIdt') + 2
                     ,INSTR((SUBSTR(v_chr_string, INSTR(v_chr_string, 'regionIdt') + LENGTH('regionIdt') + 2))
                        ,CHR(116) || CHR(0)))
                    regionId
             FROM DUAL;
       END;
     --  DBMS_OUTPUT.put_line(DTS.Form_ID);
     END LOOP;
     CLOSE c_dts;
END;

【讨论】:

  • 这并不像我希望的那样干净。尽管应该填充某些字段,但它们显示为空白。罕见但仍然不能使数据可靠。
  • 我很佩服你的毅力 ;-) 我知道 Java 并且可以“感受你”,哈哈。很高兴你有一些工作!
  • 大声笑,这是我拥有的一件事,毅力。如果有什么东西卡在我的头上,我无法放松,直到我尽我所能。我想学习java,我从哪里开始?
【解决方案2】:

这里是一个 oracle 11g java 存储函数的例子,它从 blob 中反序列化 java 对象。作为免费奖励,添加了一个 oracle java 存储过程的示例,以使用序列化的 java 对象更新 blob。

如果对象的类不是 java 内置的(如我的情况),您还需要 publish 它是 oracle 数据库中的源(包含所有依赖项)。

CREATE OR REPLACE JAVA SOURCE NAMED "ServiceParamsBLOBHandler" AS
import java.io.*;
import java.util.*;
public class ServiceParamsBLOBHandler {

    private static Object deserialize(InputStream stream) throws Exception {

        ObjectInputStream ois = new ObjectInputStream(stream);
        try {
            return ois.readObject();
        } finally {
            ois.close();
        }
    }

    private static byte[] serialize(Object object) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        oos.close();
        return baos.toByteArray();
    }

    //@SuppressWarnings("unchecked")
    private static List<Map<String, String>> getParams(oracle.sql.BLOB blob) throws Exception {
        return (List<Map<String, String>>) deserialize(blob.getBinaryStream());
    }

    public static oracle.sql.BLOB updatedParamField(oracle.sql.BLOB blob, String paramName, String fieldName, String value)
            throws Exception {

        List<Map<String, String>> params = getParams(blob);
        Map<String, String> param = getParam(params, paramName);
        param.put(fieldName, value);
        oracle.sql.BLOB res = oracle.sql.BLOB.createTemporary(blob.getOracleConnection(), true, oracle.sql.BLOB.DURATION_CALL);
        res.setBytes(1, serialize(params));
        return res;
    }

    public static void updateParamField(oracle.sql.BLOB[] blobs, String paramName, String fieldName, String value)
            throws Exception {

        oracle.sql.BLOB blob = blobs[0];
        List<Map<String, String>> params = getParams(blob);
        Map<String, String> param = getParam(params, paramName);
        param.put(fieldName, value);
        blob.truncate(0);
        blob.setBytes(1, serialize(params));
    }

    private static Map<String, String> getParam(List<Map<String, String>> params, String name) {
        for (Map<String, String> param : params) {
            if (name.equals(param.get("name"))) {
                return param;
            }
        }
        return null;
    }

    public static String getParamField(oracle.sql.BLOB blob, String paramName, String fieldName) throws Exception {
        Map<String, String> param = getParam(getParams(blob), paramName);
        return param == null ? null : param.get(fieldName);
    }

}
/

alter java source "ServiceParamsBLOBHandler" compile
--select * from SYS.USER_ERRORS
/

CREATE OR REPLACE function getServiceParamField(b IN BLOB, paramName IN VARCHAR2, fieldName IN VARCHAR2) RETURN VARCHAR2
as LANGUAGE JAVA NAME 'ServiceParamsBLOBHandler.getParamField(oracle.sql.BLOB, java.lang.String, java.lang.String) return String';
/

CREATE OR REPLACE function updatedServiceParamField(b IN BLOB, paramName IN VARCHAR2, fieldName IN VARCHAR2, value IN VARCHAR2) RETURN BLOB
as LANGUAGE JAVA NAME 'ServiceParamsBLOBHandler.updatedParamField(oracle.sql.BLOB, java.lang.String, java.lang.String, java.lang.String) return oracle.sql.BLOB';
/

CREATE OR REPLACE PROCEDURE updateServiceParamField(b IN OUT BLOB, paramName IN VARCHAR2, fieldName IN VARCHAR2, value IN VARCHAR2)
AS LANGUAGE JAVA NAME 'ServiceParamsBLOBHandler.updateParamField(oracle.sql.BLOB[], java.lang.String, java.lang.String, java.lang.String)';
/

-- oracle blob read usage example:
select getServiceParamField(byte_value, 'account', 'format') from entity_property where name='params';

-- oracle blob update with java stored function usage example:
update entity_property set byte_value=updatedServiceParamField(byte_value, 'account', 'format', '15')
where name='params' and entity_id = 123

-- oracle blob update with java stored procedure usage example:
BEGIN
   FOR c IN (select byte_value from entity_property where name='params' and entity_id = 123 for update) LOOP
       updateServiceParamField(c.byte_value, 'account', 'format', '13');
   END LOOP;
END;
/

更新

相关案例的具体 sn-ps。

1) 完整的对象加载

    private static String getVariable(oracle.sql.BLOB blob, String name) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
        try {
            //noinspection unchecked
            return ((HashMap<String, String>) ((StorageBean) ois.readObject()).variables).get(name);
        } finally {
            ois.close();
        }
    }

2) 部分场加载

    private static String getVariable(oracle.sql.BLOB blob, String name) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
        try {
            ois.skipBytes(variablesOffset);
            //noinspection unchecked
            return ((HashMap<String, String>) ois.readObject()).get(name);
        } finally {
            ois.close();
        }
    }

【讨论】:

  • 非常感谢!!!!这周我会试试看。我可能还有一些更愚蠢的问题。敬请期待:)
  • 嘿,我对java一无所知,所以请多多包涵。我需要发布什么课程,为什么?另外,我有一个存储在该 blob 中的字段列表(它是一个表,我在帖子开头有一张结构的图片)所以我在哪里输入我试图获取值的字段的名称为了?
  • 如果你想反序列化java对象,你必须对java有所了解。 ;) StorageBean 的类源需要使用CREATE OR REPLACE JAVA SOURCE 加载到oracle 中,如我的示例或loadjava 实用程序(以及所有它的依赖项,如果有的话)。但是,如果您设法以某种方式手动从 blob 中找到 variables 字段的偏移量和大小,则可以通过偏移量单独加载该字段作为内置 java.util.HashMap,而无需封闭对象的类源。
  • 完全正确。我认为我最好在 SQL 中执行它,即使它是一个糟糕的解决方案并且有很大的错误空间。所以我会接受你的答案作为答案,即使我无法检查它)))))))谢谢)))))
  • 我刚刚看到您添加了更多内容。我会试着弄清楚,如果你不介意我稍后再问一些问题。
猜你喜欢
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 2013-04-15
相关资源
最近更新 更多