Исходные данные:
Форма (создания или редактирования) сущности с полями загрузки файлов.
Системная часть спроектирована таким образом, что вначале происходить создание записи в БД, затем отдельный севрлет загружает файл в таблицу по созданному первичному ключу.
Проблема:
Если во время загрузки файла произошла ошибка, то запись будет создана, но файла не будет. В лучшем случае пользователь сможет дополнить запись, но если такая возможность не заложена в ПО, то остается битая запись с нарушенной целостностью данных.
Возможные решения:
1. После успешного сохранения данных и загрузки файлов подтверждать сущность (с помощью флага или статуса). Логика формы разбивается на следующие части: создание сущности, загрузка файлов, подтверждение сохранения.
Минусы:
На прикладному уровне необходима сборка мусора в случае, когда во время загрузки файлов произошла ошибка:
- либо сразу удалять созданные данные (сущность и успешно загруженные файлы).
- либо по расписанию удалять неподтвержденные записи.
Изменения в системной части не требуются.
2. Создавать связанные данные в одной транзакции, а именно загружать файлы вместе с данными:
2.1 Передавать CLOB/BLOB, как параметры в DB-функции. В этом решении, вероятно, будет проблемы с производительностью. Требуется доп. анализ с замерами.
2.2 Совместить реализацию DAO и JepUploadServlet севрлета. Требуется доп. анализ.
Last edit: Roman Zakharov 2018-03-26
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Думаю, нужны 2 решения - для быстрой загрузки и для долгой загрузки.
Для быстрой - делать в одной транзакции.
Для долгой - сложное решение с откатами типа п.1.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Поддержу Сашино предложение: возможно имеет смысл иметь две возможности, причем возможно для этого потребуется определить некоторую верхнюю границу (threshold), превышая которую будет целесообразнее разделять создание записи БД с загрузкой в LOB-поле. Например для JDBC метода setBinaryOutputstream или setBLOB не думаю, что будет высокой нагрузка, например, файлов размером до 2-5 мб. А вот если размер выше, то однозначно надо разделять загрузку. Исходя из этих соображений, прикладной разработчик будет иметь возможность выбора необходимого поведения.
P. S. Вместе с этим тогда следует сделать JepUploadServlet асинхронным, используя setWriteListener.
Last edit: ViTr 2018-03-26
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Думаю, нужно загружать по принципу "чем больше -- тем лучше", зачем вообще удалять данные? У нас обычно клобы/блобы -- это второстепенная информация, без которой сама запись со своими полями имеет право существовать.
а) если запись создалась, но не загрузилось фото -- пусть остаётся запись без фото (в интерфейсе это будет видно на форме просмотра, котрая обычно всплывает после сохранения + ошибка "фото не загрузилось").
б) Аналогично, если запись создалась, и успешно загрузилось 1 из 2 фото -- пусть остаётся запись с одним фото (в интерфейсе это будет видно на форме просмотра, котрая обычно всплывает после сохранения + ошибка "не все фото загрузились").
Если блоб совсем намертво привязан к записи, и последняя не имеет смысла без него, то поддерживаю создание транзакций.
Last edit: Romanov 2018-03-26
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Проблема актуальна для обоих случаев. Если пользователь хотел добавить файлы, но оказался на форме просмотра, то получается неудобно. У него должна быть возможность повторно сохранить свои файл или убрать его с формы (если он необязательный) и сохранить форму еще раз.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Саш, этот код как раз не поможет..загрузка файла происходит в отдельном потоке и передается в класс-сервлет. Имеет смысл там ее открывать, а закрывать в UploadServlet
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Напрашивается сделать сквозную функциональность TransactionManager с возможностью декларативным определением точек начал и концовки транзакции. Сейчас дело омрачает создание новой транзакции в классе BinaryFileUploadImpl
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Попробую немного подытожить:
1. Потребуется доработка JepFileField, чтобы файлы и основные данные формы были в одном запросе для обработки в одной транзакции. Для небольших файлов (3-5 МБ) можно воспользоваться 2.1, для больших 2.2;
2. Потребуется доработка UploadServlert для поддрежания асинхронной загрузки (setWriteListener).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Решать проблему с помощью развития менеджера управления транзакциями, открывать и заканчивать транзакцию в нужных местах бизнес-логики. Рефакторинг классов TextFileUploadImpl и BinaryFileUploadImpl.
Last edit: Roman Zakharov 2018-04-05
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Исходные данные:
Форма (создания или редактирования) сущности с полями загрузки файлов.
Системная часть спроектирована таким образом, что вначале происходить создание записи в БД, затем отдельный севрлет загружает файл в таблицу по созданному первичному ключу.
Проблема:
Если во время загрузки файла произошла ошибка, то запись будет создана, но файла не будет. В лучшем случае пользователь сможет дополнить запись, но если такая возможность не заложена в ПО, то остается битая запись с нарушенной целостностью данных.
Возможные решения:
1. После успешного сохранения данных и загрузки файлов подтверждать сущность (с помощью флага или статуса). Логика формы разбивается на следующие части: создание сущности, загрузка файлов, подтверждение сохранения.
Минусы:
На прикладному уровне необходима сборка мусора в случае, когда во время загрузки файлов произошла ошибка:
- либо сразу удалять созданные данные (сущность и успешно загруженные файлы).
- либо по расписанию удалять неподтвержденные записи.
Изменения в системной части не требуются.
2. Создавать связанные данные в одной транзакции, а именно загружать файлы вместе с данными:
2.1 Передавать CLOB/BLOB, как параметры в DB-функции. В этом решении, вероятно, будет проблемы с производительностью. Требуется доп. анализ с замерами.
2.2 Совместить реализацию DAO и JepUploadServlet севрлета. Требуется доп. анализ.
Last edit: Roman Zakharov 2018-03-26
Думаю, нужны 2 решения - для быстрой загрузки и для долгой загрузки.
Для быстрой - делать в одной транзакции.
Для долгой - сложное решение с откатами типа п.1.
Для быстрой, 2.1 или 2.2?
Поддержу Сашино предложение: возможно имеет смысл иметь две возможности, причем возможно для этого потребуется определить некоторую верхнюю границу (threshold), превышая которую будет целесообразнее разделять создание записи БД с загрузкой в LOB-поле. Например для JDBC метода setBinaryOutputstream или setBLOB не думаю, что будет высокой нагрузка, например, файлов размером до 2-5 мб. А вот если размер выше, то однозначно надо разделять загрузку. Исходя из этих соображений, прикладной разработчик будет иметь возможность выбора необходимого поведения.
P. S. Вместе с этим тогда следует сделать JepUploadServlet асинхронным, используя setWriteListener.
Last edit: ViTr 2018-03-26
Думаю, нужно загружать по принципу "чем больше -- тем лучше", зачем вообще удалять данные? У нас обычно клобы/блобы -- это второстепенная информация, без которой сама запись со своими полями имеет право существовать.
а) если запись создалась, но не загрузилось фото -- пусть остаётся запись без фото (в интерфейсе это будет видно на форме просмотра, котрая обычно всплывает после сохранения + ошибка "фото не загрузилось").
б) Аналогично, если запись создалась, и успешно загрузилось 1 из 2 фото -- пусть остаётся запись с одним фото (в интерфейсе это будет видно на форме просмотра, котрая обычно всплывает после сохранения + ошибка "не все фото загрузились").
Если блоб совсем намертво привязан к записи, и последняя не имеет смысла без него, то поддерживаю создание транзакций.
Last edit: Romanov 2018-03-26
Проблема актуальна для обоих случаев. Если пользователь хотел добавить файлы, но оказался на форме просмотра, то получается неудобно. У него должна быть возможность повторно сохранить свои файл или убрать его с формы (если он необязательный) и сохранить форму еще раз.
Я думаю, что в случае быстрой загрузки управление транзакцией с уровня DAO нужно перенести в JepDataServiceServlet.update/create. Сделать что-то типа:
@Override
public JepRecord update(FindConfig updateConfig) throws ApplicationException {
...
}
Саш, этот код как раз не поможет..загрузка файла происходит в отдельном потоке и передается в класс-сервлет. Имеет смысл там ее открывать, а закрывать в UploadServlet
Напрашивается сделать сквозную функциональность TransactionManager с возможностью декларативным определением точек начал и концовки транзакции. Сейчас дело омрачает создание новой транзакции в классе BinaryFileUploadImpl
Попробую немного подытожить:
1. Потребуется доработка JepFileField, чтобы файлы и основные данные формы были в одном запросе для обработки в одной транзакции. Для небольших файлов (3-5 МБ) можно воспользоваться 2.1, для больших 2.2;
2. Потребуется доработка UploadServlert для поддрежания асинхронной загрузки (setWriteListener).
Решать проблему с помощью развития менеджера управления транзакциями, открывать и заканчивать транзакцию в нужных местах бизнес-логики. Рефакторинг классов TextFileUploadImpl и BinaryFileUploadImpl.
Last edit: Roman Zakharov 2018-04-05