Корректное использование Бобов С сохранением информации с Сервлетами

У нас в настоящее время есть боб С сохранением информации, который введен в Сервлет. Проблема состоит в том, что иногда мы получаем a Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] при выполнении метода на бобе с сохранением информации.

public class NewServlet extends HttpServlet {  
    @EJB  
    private ReportLocal reportBean;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
           String[] parameters  = fetchParameters(request);
           out.write(reportBean.constructReport(parameters));
        } finally { 
            out.close();
        }
    } 
}

В вышеупомянутом коде, constructReport проверит, должно ли это открыть новое соединение с базой данных, указанной в Отчете, после которого Отчет в HTML создается из запроса, который создается из указанных параметров.

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

8
задан Bozho 20 December 2009 в 09:23
поделиться

4 ответа

Это не то, для чего предназначены сессионные компоненты с отслеживанием состояния (SFSB). Они предназначены для сохранения состояния разговора и должны быть привязаны к сеансу http пользователя для сохранения этого состояния, как тяжелая альтернатива хранению состояния непосредственно в сеансе.

Если вы хотите хранить такие вещи, как соединения с базой данных, тогда там - лучший способ сделать это.

Лучший вариант - использовать пул соединений. Вы должны всегда использовать пул соединений, и если вы работаете внутри сервера приложений (который, если вы используете EJB, то и есть), то вы можете легко использовать конфигурацию источника данных вашего сервера приложений для создания пул соединений и используйте его внутри сеансового компонента без сохранения состояния (SLSB).

9
ответ дан 5 December 2019 в 06:53
поделиться

Пока вы не предоставите код и трассировку стека, я предлагаю вам рассмотреть возможность использования пула соединений . Если под «неизвестной базой данных» вы имеете в виду базу данных, параметры которой предоставляются конечным пользователем, и, следовательно, заранее сконфигурированный пул соединений невозможен, вы все равно можете использовать концепцию пула соединений вместо того, чтобы каждый раз открывать новое соединение.

Также , theck эта ветка .

1
ответ дан 5 December 2019 в 06:53
поделиться

Дополнительная информация относительно ConcurrentAccessException: согласно спецификации EJB, доступ к SLSB синхронизируется сервером приложения. Однако, в SFSB это не так. Бремя обеспечения того, чтобы доступ к SFSB не был синхронизирован, лежит на плечах разработчика приложения.

Почему? Ну, синхронизация SLSB необходима только на уровне экземпляра. То есть, каждый конкретный экземпляр SLSB синхронизируется, но вы можете иметь несколько экземпляров в пуле или на разных узлах в кластере, и одновременные запросы на разных экземплярах не являются проблемой. К сожалению, с SFSB это не так просто из-за пассивации/активации экземпляров и репликации по всему кластеру. Вот почему спецификация не обеспечивает этого. Взгляните на эту дикуссию , если вас интересует эта тема.

Это означает, что использование SFSB из сервлета является сложным. Пользователь с несколькими окнами из одного сеанса, или перезагрузка страницы до окончания рендеринга может привести к одновременному доступу. Каждый доступ к EJB, выполняемый в сервлетах, теоретически должен быть синхронизирован на самом бобе. Я сделал это, чтобы создать InvocationHandler для синхронизации всех вызовов на конкретном экземпляре EJB:

public class SynchronizationHandler implements InvocationHandler {

 private Object target;  // the EJB

 public SynchronizationHandler( Object bean )
 {
        target = bean;
 }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
    synchronized( target )
    {
       // invoke method to the target EJB
    }
  }

}

Затем, сразу после получения удаленной ссылки на EJB, оберните ее с помощью SynchronizationHandler. Таким образом, вы уверены, что этот конкретный экземпляр не будет одновременно доступен из вашего приложения (до тех пор, пока он работает только в одном JVM). Вы также можете написать обычный класс-обертку, который синхронизирует все методы боба.

Тем не менее, мой вывод: используйте SLSB, когда это возможно.

EDIT:

Этот ответ отражает спецификации EJB 3.0 (раздел 4.3.13):

Клиентам не разрешается делать одновременные вызовы на stateful-сессию. Объект. В случае, если в настоящее время осуществляется бизнес-метод по запросу клиента на например, когда другой клиент звонит, от того же или от другого клиент, приходит к тому же самому экземпляру класса бобов сеанса, если второй клиент является клиентом бизнес-интерфейса фасоли, то одновременный вызов может привести к получению вторым клиентом javax.ejb.ConcurrentAccessException

Такие ограничения были сняты в EJB 3.1 (раздел 4.3.13):

По умолчанию клиентам разрешено делать одновременные вызовы на stateful объект сеанса и контейнер необходимы для сериализации таких одновременные запросы.

[...]

Разработчик бобов может по выбору указать, что одновременный клиент Запрещены запросы на бобы для сеансов с завязанными глазами. Это делается с использованием @AccessTimeout annotation or access-timeout deployment descriptor элемент со значением 0. В этом случае, если бизнес клиента метод находится в процессе разработки, когда другой клиент...вызванный вызов, от одного и того же или от другого клиента, приходит в один и тот же экземпляр stateful session bean, если второй клиент является клиентом бобов бизнес-интерфейс или вид без интерфейса, одновременный вызов должен привести к тому, что второй клиент получит javax.ejb.ConcurrentAccessException

14
ответ дан 5 December 2019 в 06:53
поделиться

Бобы сеанса не могут использоваться одновременно, как сказал skaffman, они предназначены для обработки состояния, соответствующего клиентскому сеансу, и обычно хранятся в объекте сеанса для каждого клиента.

Рефакторинг для использования пула баз данных для обработки параллельных запросов к вашим ресурсам - это путь, по которому нужно идти.

А пока, если все, что вам нужно, это тривиальное использование, вы можете синхронизировать вызов на конструкциюReport, как в:

synchronised (reportBean) {
       out.write(reportBean.constructReport(parameters));
}

Обратите внимание, что это не является решением, если конструктор construcReport занимает значительное количество времени относительно вашего количества клиентов.

.
0
ответ дан 5 December 2019 в 06:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: