• 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;
        }

    就能正确反序列化了

  • 相关阅读:
    搭建本地yum仓库
    linux下查看http 并发和 tcp连接数
    MySQL用户管理及SQL语句详解
    API开发之接口安全(一)----生成sign
    TP5使用API时不可预知的内部异常
    TP5通用化API接口数据封装
    根据指定日期获取近一周,及该月起止时间戳
    14-Promise
    4-字符串扩展与新增方法
    换行
  • 原文地址:https://www.cnblogs.com/alway-july/p/8398842.html
Copyright © 2020-2023  润新知