Потенциальные проблемы с созданием EntityManager для HttpSession в веб-приложении

В одном из приложений я увидел, что Entity Manager создан "для пользователя HttpSession", а EntityManagerFactory создается только один раз.

Spring или EJB НЕ используется в приложении. Менеджер сущности кэшируется в сеансе http и закрывается, когда сеанс недействителен.

public EntityManager getEntityManager() { 
    //Logic to get entity manger from session
    //If its present , then return 
    //Else create new one , entityManagerFactory.createEntityManager();
    //Put it into session and then return.
    //Returned entity manager is not closed by dao methods , 
    //but clear() is invoked
}
  • Каковы потенциальные проблемы с этим дизайном.
  • Что делать, если пользователи 100K вошли в приложение одновременно, не закончится ли соединение jdbc?
  • У каждого менеджера объектов есть отдельное соединение JDBC, связанное с ним?

Ответ 1

Ответ на 2 и 3 - да. Что касается Q1:

Одна из проблем, с которой вы столкнетесь, заключается в том, что сеансы обычно продолжаются от 2 до 24 часов (или более) после их последнего доступа. Это означает, что ваш объект сеанса попытается поддерживать открытый EntityManager, и EntityManager попытается сохранить соединение JDBC в живом и эксклюзивном для себя. Из-за этого даже у 50 пользователей в час у вас уже будет множество исключений и ошибок 500 страниц.

Я считаю, что Серж Баллеста перечислил другие серьезные проблемы, которые этот подход вызовет.

Более безопасное решение состоит в том, чтобы иметь статический ThreadLocal<EntityManager> singleton-доступ и javax.servlet.Filter для всех URL-адресов с инструкцией try-finally, которая гарантирует, что EntityManager должным образом закрыт для каждого запроса. В противном случае любое возникшее исключение приведет к зависанию соединения и вызову дополнительные проблемы.

Ответ 2

Пожалуйста, не делайте этого: вы связываете слой persistence непосредственно на веб-уровне, когда лучшие практики рекомендуют разрабатывать слоистые приложения с (свободными) ссылками только между одним слоем и только смежным.

Для реальных проблем, которые могут возникнуть с такой конструкцией, одна из них - это потеря памяти. Поскольку HTTP является не подключенным протоколом, если клиент закрывает свой браузер без явного отключения, сеанс не будет немедленно закрыт и будет собираться только по тайм-ауту сеанса. Именно поэтому лучшие практики рекомендуют хранить как можно меньше объектов в сеансе и как можно меньше. Кстати, если вы хотите обслуживать приложение на ферме серверов, объекты, хранящиеся в сеансе, должны быть сериализованы, и я не уверен, является ли диспетчер объектов. По крайней мере, это не гарантируется определением интерфейса.

Я видел такую ​​конструкцию в старом приложении, используя Hibernate, где сеанс Hibernate (более или менее эквивалентный EntityManager) был сохранен в сеансе http. Рационально было то, что, поскольку HibernateSession содержит кэш, он может ускорить приложение. Фактический результат заключался в том, что приложение требовало большого количества памяти, чтобы поддерживать только несколько сотен пользователей и никогда не будет масштабироваться для тысяч пользователей без полной перезаписи.

Я знаю, что я ответил только на 1 вопрос, потому что, но я действительно думаю, что вопрос о соединениях jdbc не является основным. Эксперимент Hibernate показал, что мы могли бы решить проблему сеанса jdbc, настроив Tomcat-пул на скорое переключение соединений jdbc и, конечно, увеличив размер пула, но до приемлемого предела. Поскольку я предполагаю, что основные реализации EntityManager могут автоматически запрашивать новый сеанс jdbc, когда они закрываются (как это делает сеанс Hibernate).