将Java对象序列化到Oracle blob列中有时会导致数据损坏
我使用序列化将一些对象保存到Oracle Blob列中,然后提取这些对象并在同一次运行或其他运行中使用 序列化/反序列化如下所示:将Java对象序列化到Oracle blob列中有时会导致数据损坏,java,oracle,serialization,jms,blob,Java,Oracle,Serialization,Jms,Blob,我使用序列化将一些对象保存到Oracle Blob列中,然后提取这些对象并在同一次运行或其他运行中使用 序列化/反序列化如下所示: public final class BytesTransformer { static BytesTransformer btInstance = new BytesTransformer(); private ByteArrayOutputStream bytesOutputStream = new ByteArrayOutputStream(); priva
public final class BytesTransformer {
static BytesTransformer btInstance = new BytesTransformer();
private ByteArrayOutputStream bytesOutputStream = new ByteArrayOutputStream();
private ObjectOutputStream objectOutputStream;
private ByteArrayInputStream bytesInputStream;
private ObjectInputStream objectInputStream;
public static BytesTransformer getInstance() {
return btInstance;
}
private void initialiseInputStreams(byte[] bytes) throws IOException {
bytesInputStream = new ByteArrayInputStream(bytes);
objectInputStream = new ObjectInputStream(bytesInputStream);
}
private void initialiseInputStreams(InputStream bytes) throws IOException {
objectInputStream = new ObjectInputStream(bytes);
}
public byte[] getBytes(Serializable sObject) throws IOException {
bytesOutputStream.reset();
objectOutputStream = new ObjectOutputStream(bytesOutputStream);
objectOutputStream.writeObject(sObject);
objectOutputStream.close();
return bytesOutputStream.toByteArray();
}
public Object fromBytes(byte[] dataBytes) throws IOException, ClassNotFoundException {
initialiseInputStreams(dataBytes);
Object sObject = objectInputStream.readObject();
closeInputStreams();
return sObject;
}
public Object fromBytes(InputStream dataBytes) throws IOException, ClassNotFoundException {
initialiseInputStreams(dataBytes);
Object sObject = objectInputStream.readObject();
closeInputStreams();
return sObject;
}
private void closeInputStreams() {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (bytesInputStream != null) {
bytesInputStream.close();
}
} catch (IOException ex) {
}
}
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE CONFIGURATION_DEFINITION SET BYTES_DATA=? WHERE NAME=?", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
preparedStatement.setObject(1, BytesTransformer.getInstance().getBytes(cfgDef));
preparedStatement.setString(2, cfgDef.getName());
preparedStatement.executeUpdate();
要将数据写入blob列,我使用如下方法:
public final class BytesTransformer {
static BytesTransformer btInstance = new BytesTransformer();
private ByteArrayOutputStream bytesOutputStream = new ByteArrayOutputStream();
private ObjectOutputStream objectOutputStream;
private ByteArrayInputStream bytesInputStream;
private ObjectInputStream objectInputStream;
public static BytesTransformer getInstance() {
return btInstance;
}
private void initialiseInputStreams(byte[] bytes) throws IOException {
bytesInputStream = new ByteArrayInputStream(bytes);
objectInputStream = new ObjectInputStream(bytesInputStream);
}
private void initialiseInputStreams(InputStream bytes) throws IOException {
objectInputStream = new ObjectInputStream(bytes);
}
public byte[] getBytes(Serializable sObject) throws IOException {
bytesOutputStream.reset();
objectOutputStream = new ObjectOutputStream(bytesOutputStream);
objectOutputStream.writeObject(sObject);
objectOutputStream.close();
return bytesOutputStream.toByteArray();
}
public Object fromBytes(byte[] dataBytes) throws IOException, ClassNotFoundException {
initialiseInputStreams(dataBytes);
Object sObject = objectInputStream.readObject();
closeInputStreams();
return sObject;
}
public Object fromBytes(InputStream dataBytes) throws IOException, ClassNotFoundException {
initialiseInputStreams(dataBytes);
Object sObject = objectInputStream.readObject();
closeInputStreams();
return sObject;
}
private void closeInputStreams() {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (bytesInputStream != null) {
bytesInputStream.close();
}
} catch (IOException ex) {
}
}
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE CONFIGURATION_DEFINITION SET BYTES_DATA=? WHERE NAME=?", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
preparedStatement.setObject(1, BytesTransformer.getInstance().getBytes(cfgDef));
preparedStatement.setString(2, cfgDef.getName());
preparedStatement.executeUpdate();
要检索数据,请执行以下操作:
public ConfigurationDefinition getConfigurationDefinition(String configName) {
byte[] bytes = null;
String sql = "SELECT BYTES_DATA FROM CONFIGURATION_DEFINITION WHERE NAME = '" + configName + "'";
ResultSet rs = getSQLConnector().executeQueryWithoutNoise(sql);
try {
if (rs == null || !rs.next()) {
return null;
}
Blob blob = rs.getBlob(blobColumnName);
bytes = blob.getBytes(1, (int) blob.length());
} catch (SQLException ex) {
GatewayLogger.error("Unable to extract db records for configuration: " + configName, ex);
return null;
} finally {
getSQLConnector().closeResultSet(rs);
}
ConfigurationDefinition aDefinition = (ConfigurationDefinition) BytesTransformer.getInstance().fromBytes(buffer);
return aDefinition;
}
大多数时候都没有问题,但有时也很少,而且似乎没有明显的模式:
java.io.StreamCorruptedException: invalid type code: <first_byte>
或
当我得到第二个错误时,我通常可以在向量中找到从几百字节开始的正确头
我应该提到的是,Oracle模式还包含一些AQ JMS队列,我使用这些队列发送类似的序列化对象,有时从Oracle表中检索这些类型的对象,尽管这两种类型的对象在代码中不可能混在一起
我环顾了有关这些例外情况的讨论,似乎没有任何东西适用于我的案例。就我所知,一切看起来都井然有序,例外情况很少出现
有什么想法吗?是否可能同时调用这些方法?那么同步可能就是一个例子。尝试使所有方法同步或不依赖实例变量。请注意,序列化对象不应真正用于长期存储。啊,我明白了。。。您的意思是,当输出流为某个线程写入时,另一个线程可能会劫持它,从而损坏消息。这是有道理的。我将同步getBytes和fromBytes方法,看看会发生什么。谢谢或者明智地利用几个当地人。会有更好的表现。一定要把它们清理干净。