StAX - чтение строки base64 из xml в базу данных - PullRequest
2 голосов
/ 01 марта 2012

Я использую 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);
 }

Этот подход поглощает память в размере, который в 6-9 раз больше моего xml. Как я могу улучшить это?

EDIT

Если я закомментирую entity.setBase64 (), то все в порядке. При сохранении байта [] в дБ использование памяти идет помешанным. Почему?

EDIT Субъекты-установщики и установщики:

    //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();
    }

EDIT xmlr.getElementText (). getBytes () по какой-то причине вызывает много использования памяти.

1 Ответ

2 голосов
/ 01 марта 2012

Как часто вы очищаете свои сущности?

Я думаю, что вы строите слишком много сущностей и недостаточно часто очищаете свой сеанс, в результате чего все эти объекты создаются для сохранения в текущем сеансе.

Возможно, вы захотите это проверить.

Редактировать

В приведенных ниже комментариях указывалось, что отправитель хотел вставить данные двоичного двоичного объекта непосредственно вбаза данных.

Вместо того, чтобы делать это в режиме гибернации, это может быть достигнуто только с помощью JDBC.

java.sql.Connection conn = ...
java.sql.PreparedStatement pstmt= conn.prepareStatement("insert into ENTITY_TABLE (BASE64) VALUES (?)");
InputStream is= ... // byte data
pstmt.setBinaryStream(1, is);
int numUpdated= pstmt.executeUpdate();

Теперь имейте в виду, это НАСТОЯЩИЙ грубый и беспорядочный.Это предполагает, что ENTITY_TABLE использует сгенерированный базой данных идентификатор для строки и что столбцы, отличные от BASE64, могут иметь значения NULL или иметь разумные значения по умолчанию.ExecuteUpdate будет запускать оператор вставки, принимая значение равное в качестве значения данных BLOB-объектов.

Надеюсь, это приблизит вас к вашему решению.

...