【问题标题】:invalid stream header during java byte deserialization from sql server从 sql server 进行 java 字节反序列化期间的流标头无效
【发布时间】:2015-07-15 09:28:37
【问题描述】:

我需要在 SQL Server 2008 表中保存一个序列化的对象流,然后对其进行反序列化。当我反序列化时出现问题..我得到以下异常:

Exception in thread "main" java.io.StreamCorruptedException: invalid stream header: 5B424065
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:804)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)

我使用的是 JTDS-1.2.4(不是最后一个 JTDS 驱动类型 4)

在我保存在列类型中的表中 -> NVARCHAR(MAX),我有这个值,例如

[B@e3fd79

我读取了上面的值(jtds 给了我一个 sql.Clob),我尝试反序列化它

我的 Java 代码:

    DocumentObjectHolder doc = new DocumentObjectHolder(xmldata, "data.xml", TYPE.XML, xmldata.getBytes("UTF-8"));
//SERIALIZE DocumentObjectHolder 
            ByteArrayOutputStream bof = new ByteArrayOutputStream();
            ObjectOutputStream serialize = new ObjectOutputStream(bof);
            serialize.writeObject(doc);
            SQLDbManagerFactory.setDbConnectionParameters(dbUri, username, password, driver);
            SQLDBManager factoryDb = SQLDbManagerFactory.getSQLDBManager();

            factoryDb.execSQL("INSERT INTO MY_DOCUMENTS (DATA,DOCUMENT_TYPE,IS_READY,DO_EMIT,IS_EMITTED)" + 
            " VALUES ( '" + bof.toByteArray() + "','" + TYPE.XML.name() + "', 0, 0, 0)");

            RecordSet rs = (RecordSet) factoryDb.execSQL("SELECT TOP 1 DATA FROM MY_DOCUMENTS");
            if (rs != null && rs.getLength() > 0){
//DESERIALIZE in DocumentObjectHolder 
                Clob objris = (Clob)rs.get(0, 0);  
                InputStream in = objris.getAsciiStream();
                byte[] b = new byte[in.available()];
                in.read(b);
                ByteArrayInputStream bais = new ByteArrayInputStream(b);
                ObjectInputStream ins = new ObjectInputStream(bais);
                DocumentObjectHolder mc =(DocumentObjectHolder)ins.readObject();
                System.out.println("Object in value ::"+mc.toString());
                ins.close();
                in.close();
            }

SQLDBManager 是我的私有库..

我想这将是 Blob(字节 blob)而不是 Clob(char lob),所以我尝试将 nvarchar(max) 更改为 varbinary(500),因为我在这里阅读: http://jtds.sourceforge.net/typemap.html

但我得到以下异常:

Exception in thread "main" java.sql.SQLException: Invalid SQL statement or JDBC escape, terminating ']' not found.
at net.sourceforge.jtds.jdbc.SQLParser.parse(SQLParser.java:1155)
at net.sourceforge.jtds.jdbc.SQLParser.parse(SQLParser.java:156)
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.<init>(JtdsPreparedStatement.java:107)
at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java:2456)
at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java:2414)

怎么了?

【问题讨论】:

    标签: java sql-server serialization bytearray deserialization


    【解决方案1】:

    让我们从“标题”5B424065 开始。

    如果你把它翻译成 ASCII,你会得到 '[' 'B' '@' 'e' ... 是不是很眼熟?

    现在你的字符串"[B@e3fd79"。它是什么?

    首先,它不是一个有效的序列化。事实上,它是什么......当你在 byte[] 上调用 toString() 时,你会得到什么。

    • "[B" 组件是byte[] 的类型签名。

    • "e3fd79" 组件是一个身份哈希码...通常基于数组地址,在首次请求身份哈希码时。

    • 最重要的是,这个字符串编码字节数组的内容/

    那么它是从哪里来的呢?

    它来自这个表达式:bof.toByteArray()。这不是将字节数组的 contents 转换为字符串的正确方法。

    什么是正确的方法?

    这取决于“DATA”列的 SQL 类型。是的 - @EJP 是正确的。您根本不应该尝试对字节数组进行字符串化。使用 PreparedStatement 参数占位符 (?)。

    如果列类型是 BINARY 或 VARBINARY,那么您应该能够按原样传递 byte[]。有关 jDTS 类型映射的完整列表,请参阅 the documentation

    【讨论】:

    • DATA 是 nvarchar(max) 然后我改为 varbinary 然后我尝试了二进制但我得到了相同的 DataTruncated Ex.. 所以使用 toByteArray() 是错误的,因为它写入了字符串字节或者是错误的 sql数据类型?
    • 也许我必须像这篇文章那样使用字符串而不是字节? -> stackoverflow.com/questions/134492/…
    • @robyp7 您根本不应该将字节数组转换为字符串。您应该使用 PreparedStatement 和 ?标记。
    猜你喜欢
    • 1970-01-01
    • 2014-04-24
    • 2016-02-10
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 2015-07-25
    • 2018-01-13
    • 1970-01-01
    相关资源
    最近更新 更多