【发布时间】:2012-03-19 17:41:42
【问题描述】:
我正在使用 StAX 读取我的文件,其中包含一些 Base64 数据,并使用 Hibernate 将其保存到数据库中。
XML:
<root>
<base64>lololencoded12</base64>
<base64>encodedlolos32</base64>
...............................
</root>
要读取和保存的代码:
xmlif = (XMLInputFactory2) XMLInputFactory2.newInstance();
xmlif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE);
xmlif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
xmlif.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE);
xmlif.configureForLowMemUsage();
List<Entity> entities = new ArrayList();
FileInputStream fis = new FileInputStream(filename);
XMLStreamReader2 xmlr = (XMLStreamReader2) xmlif.createXMLStreamReader(filename, fis);
int eventType = xmlr.getEventType();
String curElement = "";
while (xmlr.hasNext()) {
eventType = xmlr.next();
switch (eventType) {
case XMLEvent.START_ELEMENT:
curElement=xmlr.getName().toString();
if ("base64".equals(curElement)) {
Entity entity = new Entity();
entity.setBase64(xmlr.getElementText().getBytes());
session.save(entity);
session.flush();
}
break;
}
}
iterator itr = entities.iterator();
while (itr.hasNext()) {
Entity e = (Entity)itr.next();
session.saveOrUpdate(e);
}
这种方法消耗的内存量是我的 xml 大小的 6-9 倍。我该如何改进呢?
编辑
如果我注释掉 entity.setBase64() 一切都很好。将 byte[] 保存到 db 时,内存使用会变得疯狂。为什么?
编辑 实体获取器和设置器:
//for me
public byte[] getBase64() {
return base64;
}
public void setBase64(byte[] base64) {
this.base64= base64;
}
//for hibernate
public Blob getBase64Blob() {
if (this.base64!=null) {
LobCreator lobok =Hibernate.getLobCreator(MainFrame.sessionFactory.getCurrentSession());
return lobok.createBlob(base64);
} else {
return null;
}
}
public void setBase64Blob(Blob dataBlob) {
if (dataBlob!=null) {
this.base64= toByteArray(dataBlob);
}
}
//utilities methods from blob to byte array
private byte[] toByteArray(Blob fromBlob) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
return toByteArrayImpl(fromBlob, baos);
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException ex) {
}
}
}
}
private byte[] toByteArrayImpl(Blob fromBlob, ByteArrayOutputStream baos)
throws SQLException, IOException {
byte[] buf = new byte[4000];
InputStream is = fromBlob.getBinaryStream();
try {
for (;;) {
int dataSize = is.read(buf);
if (dataSize == -1)
break;
baos.write(buf, 0, dataSize);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
}
}
}
return baos.toByteArray();
}
编辑 xmlr.getElementText().getBytes() 由于某种原因导致大量内存使用。
【问题讨论】:
-
您是否分析了这段代码的内存消耗?记忆去哪儿了?
-
我可以看到内存使用峰值是实际 xml 大小的 6 倍。
-
我可以看到分配了很多 char[] 和 byte[]
-
用
session.saveOrUpdate(e);替换entities.add(entity); -
问:您需要将二进制 base64 编码的 blob 以什么表示形式存储在数据库中?只是编码文本留在 base64 中,还是对 setBase64 的调用实际上将 base64 文本解码回二进制数据,作为 blob 存储在您的数据库中?这个细节可能会有所帮助。
标签: java xml hibernate sax stax