时间:2021-07-01 10:21:17 帮助过:29人阅读
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 反序列化错误
标签:tin 集成 void trace 失败 ssi apply tsql rip