oracle blob 反序列化错误

代码的目的是先将一个配置类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;
    }

就能正确反序列化了

原文地址:https://www.cnblogs.com/alway-july/p/8398842.html