powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / EntityManager в отдельном потоке
11 сообщений из 11, страница 1 из 1
EntityManager в отдельном потоке
    #39236866
dymka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте!

Вот потихоньку начал ковырять java ee. И возникла проблема, которую ну никак решить не могу - туплю зверско.

Есть класс Main @Singleton @Startup. Инжектится TimerService, EntityManager (EntityManagerFactory).
В методе @PostConstruct создается таймер.

По событию таймера нужно запустить долгий процесс (для этого стартуем поток). В этом процессе нужно скидывать инфу в БД.

Примерный код такой:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
   
    @Timeout 
    private void timeout(Timer timer) {
        final ProjectSchedule schedule = (ProjectSchedule) timer.getInfo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                final ProjectLog log = new ProjectLog(schedule);
                EntityManager em = emf.getEntityManager(); //emf injected 
                UserTransaction utx = sessionContext.getUserTransaction(); // sessionContext injected
                try {
                    utx.begin();
                    em.persist(log);
                    utx.close();
                    em.close();
                } catch (Exception ex) {
                    System.out.println("EXCEPTIION: " + ex.getMessage()); //это просто так 
                }
            }
        }
        ).start();
}



Это простой пример, на самом деле процесс может занимать час-два. Не суть. Если запускать без потока, то все работает (em беру заинжектенный), если в потоке, то никак не могу заставить заработать.
Сервер Wildfly 9.0.2. Приложение Enterprise (EAR+EJB+WEB).
ProjectSchedule, ProjectLog - entities.
Может есть смысл по-другому построить все?
В данном примере ничего не происходит. Все работает, но в БД ничего не вставляется.
При попытке использовать транзакции em - NullPointerException.

Скорее я просто не понимаю концепцию EE/Beans или еще как торможу. Буду признателен за любые советы. Спасибо.
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39236870
dymka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Немного накосячил с сорцами, пока выкладывал:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
   
    @Timeout 
    private void timeout(Timer timer) {
        final ProjectSchedule schedule = (ProjectSchedule) timer.getInfo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                final ProjectLog log = new ProjectLog(schedule);
                EntityManager em = emf.createEntityManager(); //emf injected 
                UserTransaction utx = sessionContext.getUserTransaction(); // sessionContext injected
                try {
                    utx.begin();
                    em.persist(log);
                    utx.commit();
                    em.close();
                } catch (Exception ex) {
                    System.out.println("EXCEPTIION: " + ex.getMessage()); //это просто так 
                }
            }
        }
        ).start();
    }
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39236871
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dymkaПо событию таймера нужно запустить долгий процесс (для этого стартуем поток).
Скорее я просто не понимаю концепцию EE...
Если вы собираетесь понять концепции EE, то начните хотя бы с чтения EE спецификации. Это относительно небольшой PDF документ, который в конкретные технологии не углубляется. И в нем написано, что согласно EE вам строго на строго не рекомендуется писать код вида new Thread().start();

Причина этого достаточно банальна. Контейнер создаёт кучу ThreadLocal для каждого потока и хранит там массу контекста. EM aka Unit Of Work имеет тот же жизненный цикл как и запрос-ответ. И каждый запрос использует свой собственный экземпляр EM. И как же серверу это удаётся? Именно через ThreadLocal. Когда вы создаёте свой собственный поток, то сервер понятия не имеет что к нему и как привязать.

Какая глубокая нужда вас заставила использовать Thread.start() - не понятно. Если вы уже используете JEE таймер, то он и так должен быть многопоточным и асинхронным к клиентским запросам. Какую задачу вы пытаетесь решить запустив асинхронный процесс внутри асинхронного процесса? Ну, если нужна какая-то в этом есть, то в JEE API есть и классы для запуска асинхронных задач. java.lang.Thread к ним не относится.
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39236883
dymka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz, ну глупый пока я в EE ))) Почитаю спеки.

Если без потоков я делаю sleep (эмулирую длительность, хотя может тоже неверно так) внутри @timeout, то повторный вызов по следующему таймеру почему-то ждет выполнения первого. Я так и думал что timeout асинхронный. Может от настроек AS зависит, но по таймеру там нет ничего толком. Или я неверно интерпретировал записи, которые оказываются в БД. Время старта следующего timeout оказывается смещенным на время задержки-интервал расписания. Поразбираюсь еще с этим.

Thread.start - да первое, что попалось на глаза.
Как таковых клиентских запросов нет. Это как бы крутится само собой. Синглтон и стартап. Может запускаться несколько процессов, могут быть асинхронными.

А какой лучше взять для этой цели класс для запуска асинхронной задачи? Ну если с таймером не разберусь? :)
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39236888
rema174
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dymkaА какой лучше взять для этой цели класс для запуска асинхронной задачи?
тут найдеш, меня тоже Blazkowicz научил :-)
http://stackoverflow.com/questions/4691132/how-to-run-a-background-task-in-a-servlet-based-web-application
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39236889
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dymka,

https://docs.jboss.org/author/display/WFLY8/EJB3 subsystem configuration guide
Смотрите настройки Timer Service и его thread pool
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39236890
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39237174
dymka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz, rema174 большое спасибо!

Пока сделал так, хотя опять не уверен ни в чем :).
Если что-то тут работает, то это не означает, что все сделано правильно...

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
    
    @Timeout 
    @Lock(LockType.READ)
    @AccessTimeout(value = 120, unit = TimeUnit.MINUTES)
    private void timeout(Timer timer) {
        Integer scheduleId = (Integer) timer.getInfo();
        ProjectSchedule schedule = em.find(ProjectSchedule.class, scheduleId);
        ProjectLog log = new ProjectLog(schedule);
        em.persist(log);
        Project project = findProject(schedule.getProjectID());
        ProjectStatus status = project.start(schedule); //длительная операция (10-120 минут)
        log.setStatus(status);
        em.persist(log);
        em.detach(log);
    }



В конфиге все ок - пул = 10. Этого мне достаточно.
1. Собственно вопрос - можно делать такие таймауты? Или это не по "феншую"?
2. Или все же использовать ScheduleExecutorService?
3. Если мне больше объект log не нужен - правильно делать detach?
4. И если все же произойдет повторный вход в timeout с истечением времени AccessTimeout, то можно ли каким-либо образом перехватить этот Exception?
5. И еще вопрос: если я в качестве Info таймера передаю сущность, то она приходит в таймер, но без объектов OneToMany. Они остаются неинициализированными. Поэтому в примере выше я передаю ID и заново делаю запрос. Это нормально?

Много, конечно, вопросов, сам буду разбираться еще.
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39237177
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dymka1. Собственно вопрос - можно делать такие таймауты? Или это не по "феншую"?

Какие такие? Зачем тут вообще таймаут?

dymka2. Или все же использовать ScheduleExecutorService?

Буква потерялась.
Вы таймер от таймаута не отличаете? ScheduledExecutorService имеет все те же проблемы в JEE что и ThreadStart. Если только вы его не создали средствами контейнера. Если его создаёт сам контейнер, то им, скорее всего, можно смело пользоваться.

dymka3. Если мне больше объект log не нужен - правильно делать detach?

Полагаю что "нет".

dymka4. И если все же произойдет повторный вход в timeout с истечением времени AccessTimeout, то можно ли каким-либо образом перехватить этот Exception?
Почему "повторный вход" вдруг должен вызывать исключение?

dymka5. И еще вопрос: если я в качестве Info таймера передаю сущность, то она приходит в таймер, но без объектов OneToMany. Они остаются неинициализированными. Поэтому в примере выше я передаю ID и заново делаю запрос. Это нормально?

Google -> JPA Lazy Initialization. Вообще это странно, что "с пустыми". Должно быть исключение ленивой инициализации.
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39237393
dymka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,

1, 4. Если оставить только @Timeout, то если будет запущена по расписанию вторая задача, в то время когда первая еще не закончилась, то выходит следующее:
Error invoking timeout for timer: ... javax.ejb.ConcurrentAccessTimeoutException

Но вот перегрузил комп, удалил деплой, заново залил и заработало без AccessTimeout... уфф ))

2. Именно, как заинжектенный компонент (@Resource), ибо, как понял, такие правила игры :). Но если будет работать вариант с TimerService и @Timeout - то это мне тоже не надо. Хочу как проще. TimerService так то идеально, если справлюсь.

3. А что нужно сделать, чтобы объект был сохранен в БД, а потом из памяти удален. Т.е. убрать из управления EM. Ладно, сам покопаюсь еще.

5. Да все верно, исключение при обращении к этим свойствам. Неверно выразился. Просто у этого объекта до таймера есть эти объекты, а в timeout они "пропадают" ). На данном этапе освоения технологии меня такие вещи просто обескураживают.

Спасибо большое, не хочу больше отнимать чужое время, буду разбираться с тем, что есть.
...
Рейтинг: 0 / 0
EntityManager в отдельном потоке
    #39237436
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dymka1, 4. Если оставить только @Timeout, то если будет запущена по расписанию вторая задача, в то время когда первая еще не закончилась, то выходит следующее:
Error invoking timeout for timer: ... javax.ejb.ConcurrentAccessTimeoutException

Это уже нюансы EJB. Если у вас Stateful бин или Singleton, то это вполне логично. EJB пытается обезопасить состояние от конкурентного доступа. А как на счет Stateless бина? Вообще у EJB так много подобных заморочек, что я бы сильно подумал перед тем как предпочесть JEE стэк Spring Framework-у.

dymka2. Именно, как заинжектенный компонент (@Resource), ибо, как понял, такие правила игры :). Но если будет работать вариант с TimerService и @Timeout - то это мне тоже не надо. Хочу как проще. TimerService так то идеально, если справлюсь.

Ну, тогда должно работать. Да.

dymka3. А что нужно сделать, чтобы объект был сохранен в БД, а потом из памяти удален. Т.е. убрать из управления EM. Ладно, сам покопаюсь еще.
Ну, как бы ничего не надо делать. EM надо закрыть. Но это контейнер должен сделать и сам при выходе из транзакции. Просто надо убедиться что EM закрывается.
А сам объект из памяти потом GC соберет. Это вообще отдельная тема.

dymka5. Да все верно, исключение при обращении к этим свойствам. Неверно выразился. Просто у этого объекта до таймера есть эти объекты, а в timeout они "пропадают" ). На данном этапе освоения технологии меня такие вещи просто обескураживают.
Ассоциации One2Many по-умолчанию грузятся лениво (отложено). Это надо знать. Это JPA и ORM с кучей подводных нюансов.
Ленивые ассоциации имеют внутри ссылку на сессию (EntityManager) и используют его чтобы загрузить зависимости, только тогда когда они действительно нужны. Если в одном потоке EntityManager закрыть (а контейнер это сделает сам по завершении транзакции), то в другом потоке догрузить ассоциации уже нельзя, так как EM закрыт.
Можно тупо передать ID и прогрузить объект заново. Все же кэш второго уровня решает.
Можно использовать Fetch и загрузить всё что нужно заранее - до закрытия EM. Тогда объект спокойно можно скормить в другой поток.

dymkaСпасибо большое, не хочу больше отнимать чужое время, буду разбираться с тем, что есть.
Раньше JEE был большим и сложным. Всё нужно было писать руками. Теперь писанины руками меньше, то зато всё большое и сложное осталось внутри скрытым от разработчика. Поэтому понять всё это очень сложно. Технологии очень жирные с кучей подобных нюансов. Но JPA надо изучать. Хороших альтернатив ORM-ам пока не видно.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / EntityManager в отдельном потоке
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]