1. 程式人生 > >oracle blob 反序列化錯誤

oracle blob 反序列化錯誤

exc oda 沒有 spa error long org apach output

代碼的目的是先將一個配置類JobConfig序列化存進Oracle中的Blob中,然後查的時候反序列化出來。

先看一下控制臺報錯

### Cause: com.audaque.lib.core.exception.AdqRuntimeException: error on getResult; nested exception is java.io.StreamCorruptedException: invalid stream header: 00540001
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:
23) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:107) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:98) at sun.reflect.GeneratedMethodAccessor133.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
43) at java.lang.reflect.Method.invoke(Method.java:498) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:354) ... 84 more Caused by: com.audaque.lib.core.exception.AdqRuntimeException: error on getResult; nested exception is java.io.StreamCorruptedException: invalid stream header:
00540001 at com.audaque.datadiscovery.mybatis.SerializeHandler.getResult(SerializeHandler.java:50) at org.apache.ibatis.executor.resultset.FastResultSetHandler.getPropertyMappingValue(FastResultSetHandler.java:325) at org.apache.ibatis.executor.resultset.FastResultSetHandler.applyPropertyMappings(FastResultSetHandler.java:301) at org.apache.ibatis.executor.resultset.NestedResultSetHandler.getRowValue(NestedResultSetHandler.java:135) at org.apache.ibatis.executor.resultset.NestedResultSetHandler.handleRowValues(NestedResultSetHandler.java:102) at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleResultSet(FastResultSetHandler.java:188) at org.apache.ibatis.executor.resultset.NestedResultSetHandler.handleResultSet(NestedResultSetHandler.java:73)

Mybatis resultMap

  <resultMap type="com.audaque.datadiscovery.job.model.po.Job" id="Job">
        <id property="jobId" column="JOB_ID" />
        <result property="jobName" column="JOB_NAME" />
        <result property="createTime" column="CREATE_TIME" />
        <result property="description" column="DESCRIPTION" />
        <result property="executeTime" column="EXECUTETIME" />
        <result property="jobConfig" column="JOB_CONFIG" typeHandler="com.audaque.datadiscovery.mybatis.SerializeHandler" />
        <association property="creator" columnPrefix="creator_" resultMap="User" />
    </resultMap>
    

報錯原因是查詢後設置結果時,Job對象的JobConfig屬性反序列化失敗。

使用的是MyBatis框架,針對這個JobConfig 配置類,做了一個TypeHanlder,下面是這個TypeHandlder

public class SerializeHandler implements TypeHandler<Object> {

@Override
public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
ps.setString(i, null);
return;
}
try {
byte[] ss = SerializeUtils.serializeObject(parameter);
ps.setBytes(i, ss);
} catch (IOException e) {
throw new AdqRuntimeException("error on setParameter" ,e);
}
}

@Override
public Object getResult(ResultSet rs, String columnName) throws SQLException {
Object object = null;
try {
      //反序列化報錯
object = SerializeUtils.deserializeObject(rs.getBytes(columnName));
} catch (IOException e) {
throw new AdqRuntimeException("error on getResult" ,e);
} catch (ClassNotFoundException e) {
throw new AdqRuntimeException("error on getResult" ,e);
}
return object;
}

@Override
public Object getResult(CallableStatement cs, int columnIndex)
throws SQLException {
Object object = null;
try {
object = SerializeUtils.deserializeObject(cs.getBytes(columnIndex));
} catch (IOException e) {
throw new AdqRuntimeException("error on getResult" ,e);
} catch (ClassNotFoundException e) {
throw new AdqRuntimeException("error on getResult" ,e);
}
return object;
}


@Override
public Object getResult(ResultSet rs, int columnIndex) throws SQLException {
Object object = null;
try {
object = SerializeUtils.deserializeObject(rs.getBytes(columnIndex));
} catch (IOException e) {
throw new AdqRuntimeException("error on getResult" ,e);
} catch (ClassNotFoundException e) {
throw new AdqRuntimeException("error on getResult" ,e);
}
return object;
}

}

TypeHandler中有一個序列化工具類

public final class SerializeUtils {

    /**
     * 
     * @param object is want to serialize
     * @return
     * @throws IOException
     */
    public static <T> byte[] serializeObject(T object) throws IOException {
        byte[] buffer = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        long start = System.currentTimeMillis();
        try{
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(object);
            oos.flush();
            buffer =  bos.toByteArray();
        }catch(IOException ex){
            throw ex;
        }finally{
            if(oos != null){
                oos.close();
            }
            if(bos != null){
                bos.close();
            }
            long end = System.currentTimeMillis();
//            System.out.println("serializeObject "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(start))+" costs "+(end-start) + " ms");
        }
        return buffer;
    }
    
    /**
     * 
     * @param buf is want to deserialize
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @SuppressWarnings({ "unchecked" })
    public static <T> T deserializeObject(byte[] buf) throws IOException, ClassNotFoundException {
        T object = null;
        ByteArrayInputStream bis = null; 
        ObjectInputStream ois = null;
        long start = System.currentTimeMillis();
        try{
            bis = new ByteArrayInputStream(buf);
            ois = new ObjectInputStream(bis);
            object = (T) ois.readObject();
        }catch(IOException ex){
            throw ex;
        }finally{
            if(ois != null){
                ois.close();
            }
            if(bis != null){
                bis.close();
            }
            long end = System.currentTimeMillis();
//            System.out.println("deserializeObject "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(start))+" costs "+(end-start) + " ms");
        }
        return object;
    }

我先測試了工具類SerializeUtils是否有問題,測試了一下是沒有問題的。

我在序列化之後調用反序列化方法,也是沒有問題的。

問題出在從數據庫查詢出來後,查了一下讀取BLOB對象為byte的java代碼,java.sql.Blob對象轉化byte數組 和 oracle.sql.Blob對象轉化byte數組的方法不同,如果使用 oracle.sql.Blob.getBytes方法轉化,則會報java.io.StreamCorruptedException: invalid stream header: 006C0001 錯誤

    QueryRunner run = new QueryRunner(true);

        String  querySql  = "SELECT JOB_CONFIG FROM adqm_job where job_id = 141";


        Object[] array = run.query(con, querySql, new ArrayHandler());

        Blob blob= (Blob) array[0];

        byte[] returnValue =  blob.getBytes(1, (int) blob.length());

        System.out.println(Arrays.toString(returnValue));


        InputStream is = null;
        BLOB blob1 = (BLOB)(array[0]);
        byte[] b = null;
        try {
            is = blob1.getBinaryStream();
            b = new byte[(int) blob1.length()];
            is.read(b);
        } catch (Exception e) {
            e.printStackTrace();
        }

但是系統代碼使用的是 rs.getBytes(columnName)代碼,那是否是getBytes代碼有問題嗎?

        Connection con = DBUtil.getConnection();
        String  querySql  = "SELECT JOB_CONFIG FROM adqm_job where job_id = 141";
        PreparedStatement preparedStatement =  con.prepareStatement(querySql);
        ResultSet resultSet =  preparedStatement.executeQuery();
        while (resultSet.next())
        {
            byte []bytes= resultSet.getBytes("JOB_CONFIG");
            SerializeUtils.deserializeObject(bytes);
        }
        DBUtil.close(con);

測試了一下使用 rs.getBytes(columnName) 取出byte數組是 反序列化是沒有問題的。

BUG的原因還是沒有找到,我猜想的原因是object = SerializeUtils.deserializeObject(rs.getBytes(columnName)); 中rs.getBytes(columnName)的底層實現為((BLOB)(rs.getBlob)).getBytes();

最後我將TypeHandler 的getResult方法中改為

@Override
    public Object getResult(ResultSet rs, String columnName) throws SQLException {
        Object object = null;

        // 集成工作流BUG修復
       try {
            Blob blob = rs.getBlob(columnName);
            byte[] returnValue = null;
            if (null != blob) {
                returnValue = blob.getBytes(1, (int) blob.length());
                object =  SerializeUtils.deserializeObject(returnValue);
            }
        //     代碼
        //    object =  SerializeUtils.deserializeObject(rs.getBytes(columnName));

        } catch (IOException e) {
            throw new AdqRuntimeException("error on getResult" ,e);
        } catch (ClassNotFoundException e) {
            throw new AdqRuntimeException("error on getResult" ,e);
        }
        return object;
    }

就能正確反序列化了

oracle blob 反序列化錯誤