Настройка производительности операции проекта Hibernate + Spring + MySQL, в которой хранятся изображения, загруженные пользователем.

Я работаю над веб-проектом на основе Spring + Hibernate + MySQL. Я застрял в точке, где мне нужно хранить изображения, загруженные пользователем в базу данных. Хотя я написал код, который на данный момент работает хорошо, но я считаю, что когда проект будет запущен, все будет плохо.

Вот мой предметный класс, который несет байты изображения:

@Entity
public class Picture implements java.io.Serializable{
    long id;
    byte[] data;
    ... // getters and setters
}

А вот мой контроллер, который сохраняет файл при отправке:

public class PictureUploadFormController extends AbstractBaseFormController{
    ...
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception{
         MutlipartFile file; 
         // getting MultipartFile from the command object
         ...
         // beginning hibernate transaction
         ...
         Picture p=new Picture();
         p.setData(file.getBytes());
         pictureDAO.makePersistent(p); // this method simply calls getSession().saveOrUpdate(p)

         // committing hiernate transaction
         ...
    }
    ...
}

Очевидно, плохой код. Могу ли я использовать InputStream или Blob для сохранения данных вместо того, чтобы сначала загружать все байты от пользователя в память, а затем помещать их в базу данных?

Я провел некоторое исследование поддержки Hibernate для Blob и нашел это в книге Hibernate In Action:

java.sql.Blob и java.sql.Clob - наиболее эффективный способ обработки больших объектов в Java. К сожалению, экземпляр Blob или Clob можно использовать только до завершения транзакции JDBC. Итак, если ваш постоянный класс определяет свойство java.sql.Clob или java.sql.Blob (в любом случае, это не очень хорошая идея), вы будете ограничены в том, как можно использовать экземпляры класса. В частности, вы не сможете использовать экземпляры этого класса как отдельные объекты. Кроме того, многие драйверы JDBC не имеют рабочей поддержки для java.sql.Blob и java.sql.Clob. Следовательно, имеет смысл отображать большие объекты с использованием двоичного или текстового типа сопоставления, предполагая, что извлечение всего большого объекта в память не снижает производительность.

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

Теперь очевидно нельзя использовать Blob, так как это в любом случае не очень хорошая идея, что еще можно использовать для повышения производительности? Мне не удалось найти ни обновленных шаблонов дизайна, ни какой-либо полезной информации на веб-сайте Hibernate. Поэтому мы будем очень благодарны за любую помощь / рекомендации от stackoverflowers.

Спасибо


person craftsman    schedule 02.05.2010    source источник


Ответы (1)


В исправленном издании книги (Сохранение Java с Hibernate) говорится:

В таблице 5.3 перечислены типы гибернации для обработки двоичных данных и больших значений. Обратите внимание, что в качестве типа свойства идентификатора поддерживается только binary.

Mapping type   Java type   Standard SQL built-in type
binary         byte[]               VARBINARY
text           java.lang.String     CLOB
clob           java.sql.Clob        CLOB
blob           java.sql.Blob        BLOB
serializable   Any Java class that  VARBINARY
               implements
               java.io.Serializable

Если свойство в вашем постоянном классе Java имеет тип byte[], Hibernate может сопоставить его со столбцом VARBINARY с типом двоичного сопоставления. (Обратите внимание, что реальный тип SQL зависит от диалекта; например, в PostgreSQL тип SQL - BYTEA, а в Oracle - RAW.) Если свойство в вашем постоянном классе Java имеет тип java.lang.String, Hibernate может сопоставьте его со столбцом SQL CLOB с типом сопоставления текста.

Обратите внимание, что в обоих случаях Hibernate инициализирует значение свойства сразу, когда загружается экземпляр сущности, содержащий переменную свойства. Это неудобно, когда вам приходится иметь дело с потенциально большими значениями.

Одним из решений является отложенная загрузка посредством перехвата доступа к полям по запросу. Однако этот подход требует оснащения ваших постоянных классов байт-кодом для внедрения дополнительного кода. Мы обсудим отложенную загрузку с помощью инструментовки и перехвата байт-кода в главе 13, раздел 13.1.6, «Ленивая загрузка с перехватом».

Второе решение - это свойство другого типа в вашем классе Java. JDBC поддерживает объекты локатора (LOB) напрямую.1 Если ваше свойство Java имеет тип java.sql.Clob или java.sql.Blob, вы можете сопоставить его с типом сопоставления clob или blob, чтобы получить ленивую загрузку больших значений без инструментария байт-кода. . Когда владелец свойства загружен, значение свойства является объектом-указателем, то есть указателем на реальное значение, которое еще не материализовалось. Как только вы получаете доступ к свойству, значение материализуется. Эта загрузка по запросу работает только до тех пор, пока транзакция базы данных открыта, поэтому вам необходимо получить доступ к любому свойству такого типа, когда экземпляр объекта-владельца находится в постоянном и транзакционном состоянии, а не в отсоединенном состоянии. Ваша модель предметной области теперь также привязана к JDBC, поскольку требуется импорт пакета java.sql. Хотя классы модели предметной области выполняются в изолированных модульных тестах, вы не можете получить доступ к свойствам LOB без подключения к базе данных.

Надеюсь это поможет.

person Péter Török    schedule 02.05.2010