Spring MVC + Oracle LOB + потоковая передача

Мне нужно отправить двоичный поток большого двоичного объекта с помощью ServletOutputStream.

Я использую следующие технологии и программное обеспечение: Oracle 11, WebSphere 7, Springframework 2.5.5, Hibernate 3.3.SP1.

Есть две базы данных Oracle. Первая содержит таблицы для описания документов, которые я должен передать, а вторая - содержание документов.

Весной я также настроил поддержку источников данных XA в WebSphere и JtaTransactionManager.

Я получаю ссылку на документ и сам контент в одной транзакции.

Спецификация JDBC говорит нам, что большие объекты являются транзакционными объектами, и переносимые приложения должны использовать такие объекты в транзакциях.

А у меня следующие вопросы:

  1. Законно ли извлекать входной поток BLOB в транзакционном методе и передавать его нетранзакционному методу верхнего уровня? Что-то вроде этого:

    @Transactional
    public InputStream getContent(Long docId) {
        Blob blob = getBlob(...);
        return blob.getBinaryStream();
    }


    public ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse resp) {
       Long docId = ServlerRequestUtils.getRequiredLongParameter(req);
       InputStream is = service.getContent(docId);
       copy(is, resp.getOutputStream());
       return null;
    }
  1. Если это не законно, как передать двоичный поток BLOB конечному пользователю, если содержимое BLOB достаточно велико и на сервере приложений предварительно настроено время ожидания транзакции? Должен ли я обрабатывать транзакции вручную и устанавливать время ожидания равным нулю (транзакция никогда не истекает)?

  2. Как в таком случае лучше всего передать двоичный поток BLOB конечному пользователю?


person szhem    schedule 14.01.2010    source источник


Ответы (1)


Вы правы в том, что возвращать поток BLOB из вашего метода tx не очень хорошая идея... это может работать при определенных обстоятельствах, в зависимости от базы данных, но это рискованно.

Решение состоит в том, чтобы вывернуть проблему наизнанку. Передайте OutputStream сервлета в ваш транзакционный метод. Это позволяет избежать проблем с транзакциями и позволяет обрабатывать потоки в одном месте:

@Transactional
public void getContent(Long docId, OutputStream outputStream) {
    Blob blob = getBlob(...);
    InputStream blobStream = blob.getBinaryStream();
    copy(blobStream, outputStream);
    blobStream.close(); // ignoring the usual stream closing try/catch stuff for brevity
}

public ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse resp) {
   Long docId = ServlerRequestUtils.getRequiredLongParameter(req);
   service.getContent(docId, resp.getOutputStream());
   return null;
}
person skaffman    schedule 14.01.2010
comment
Большое спасибо, я сделал что-то подобное, и теперь меня беспокоит время ожидания транзакции, особенно когда соединение пользователя достаточно медленное, а контент, который я должен передать, достаточно велик. Можно ли установить тайм-аут транзакции на транзакцию без тайм-аута? - person szhem; 15.01.2010
comment
Абсолютно не проблема это сделать - person skaffman; 15.01.2010
comment
Еще раз спасибо за помощь в поиске приемлемого решения :) - person szhem; 15.01.2010