Spring MVC + Oracle LOB + потоковая передача
Вопрос
Мне нужно отправить двоичный поток большого двоичного объекта с помощью ServletOutputStream.
Я использую следующие технологии и программное обеспечение:Oracle 11, WebSphere 7, Springframework 2.5.5, Hibernate 3.3.SP1.
Есть две базы данных Oracle.В первой находятся таблицы описания документов, которые мне необходимо передать, а во второй - содержание документов.
Весной я также настроил поддержку источников данных XA в WebSphere и JtaTransactionManager.
Я получаю ссылку на документ и сам контент за одну транзакцию.
Спецификация JDBC сообщает нам, что LOB — это транзакционные объекты, и переносимые приложения должны использовать такие объекты в транзакциях.
И у меня есть следующие вопросы:
- Законно ли получать входной поток 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;
}
Если это незаконно, как передать двоичный поток BLOB-объекта конечному пользователю, если содержимое BLOB-объекта достаточно велико и на сервере приложений задан предварительно настроенный тайм-аут транзакции?Должен ли я обрабатывать транзакции вручную и устанавливать тайм-аут равным нулю (транзакция никогда не истекает)?
Как в таком случае лучше всего передать двоичный поток BLOB конечному пользователю?
Решение
Вы правы в том, что возврат потока 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;
}