2012-06-27 4 views
5

Следующий код запускается всякий раз, когда я хочу сохранить любую сущность. Кажется, что все работает нормально, но я не понимаю, как это работает!Как работает JPA-транзакция

EntityManager em = getEntityManager(); 
EntityTransaction userTransaction = em.getTransaction(); 
userTransaction.begin(); 
em.persist(ent); 
userTransaction.commit(); 

EntityManager, приведенный выше, представляет собой единый экземпляр, общий для всего приложения. После начала транзакции; Я просто говорю em.persist (entity) .. Как hibernate знает, что это принадлежит к какой транзакции!

Предположим, что в моем приложении 10 одновременных пользователей и все 10 потоков, выполняющихся над кодом. Таким образом, создается и совершено 10 независимых транзакций. Но все 10 разных организаций я не связываю их с их соответствующими транзакциями; так как JPA может это исправить!

Основываясь на ответах; мы имеем ниже; мы говорим, что у нас должен быть экземпляр EntityManager для потока? Не будет ли это убийство на сервере! Должны ли мы объединять эти экземпляры? Не будет ли это равносильно повторению реализации пула соединений?

+2

Что вы подразумеваете под «какой транзакцией»? EM имеет единую (локальную) транзакцию в любое время; он не имеет нескольких. Совместное использование одного EM в нескольких потоках - это рецепт проблем, поскольку он не гарантируется потокобезопасностью. – DataNucleus

+0

http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/transactions.html EntityManagerFactory - это дорогостоящий, потокобезопасный объект, предназначенный для совместного использования всеми потоками приложений. Он создается один раз, обычно при запуске приложения. EntityManager - недорогой, не-потоковый объект, который должен использоваться один раз, для одного бизнес-процесса, одной единицы работы, а затем отбрасывается – Deepak

+0

. я понимаю, что создание EntityManager является легким, но все же не очень легким, что для каждой небольшой операции с БД мы ее создаем. Предлагаемое решение - создать EM для каждого запроса. Итак, похоже, что он должен быть на уровне ThreadLocal. – Deepak

ответ

4

Это работает, потому что вам повезло. К счастью, означает, что фиксация и начало вызываются в правильном порядке - случайно.

Вы используете один экземпляр диспетчера объектов из нескольких потоков. Это неправильно, потому что это не гарантирует безопасность потоковой передачи. Доступ к транзакции уровня ресурса через EntityTransaction привязан к экземпляру диспетчера сущностей, а не к потоку.

Таким образом, вы используете одно и то же EntityTransaction и используете его с успехом последовательно для нескольких транзакций. Использование его последовательно для strart и завершения нескольких транзакций в порядке, но использование его из многих потоков не является.

В hibernate (4.1.4) ссылка хранится в поле экземпляра tx в классе AbstractEntityManageImpl, но это только деталь реализации.

+0

мы говорим, что у нас должен быть экземпляр EntityManager для потока? Не будет ли это убийство на сервере! Должны ли мы объединять эти экземпляры? Не будет ли это равносильно повторению реализации пула соединений? – Deepak

+2

EntityManager - довольно легкий объект для создания, EntityManagerFactory - это тяжелый вес. Нет причин для запуска менеджеров объектов пула. –

+0

Я понимаю, что EntityManager не является потокобезопасным, для которого мы должны создавать новые объекты. Но нужно ли нам создавать новые EntityManager для выбора запроса (для которого мы не запускаем никаких транзакций). Не будет ли это излишним? – Deepak

1

Сделка связана с текущим потоком каким-то образом, используя переменную ThreadLocal.

+1

Так что дизайн выше безупречен или нет! Я все еще смущен! – Deepak

+0

Все зависит от того, как вы получаете экземпляр EntityManager. Если он вводится в EJB или в Spring beans (как объясняется в документации Spring), EntityManager фактически является прокси-сервером для реализации реального EntityManager. Если нет, см. Ответ Микко Мауну. –

+1

Я понимаю, что EntityManager не является потокобезопасным, для которого мы должны создавать новые объекты. Но нужно ли нам создавать новые EntityManager для выбора запроса (для которого мы не запускаем никаких транзакций). Не будет ли это излишним? – Deepak

0

Я рекомендую вам понять, как JTA работает независимо от Hibernate - это очень важно для ваших понять
Кроме того, читать об управляемом контейнере транзакциях и фасоли управляемых сделках.
Если вы работаете в транзакции, управляемой контейнером, вы можете указать для компонента, который вы введете EntityManager в область транзакции -
например - если область ТРЕБУЕТСЯ, это означает, что если другой компонент вызывает этот компонент, а не в контексте транзакции, новая транзакция будет открыта. Если транзакция уже существует, вы будете использовать ту же транзакцию. Важно понимать это, поскольку транзакции - это дорогостоящий ресурс в вашей системе.

Объект операции связан с ThreadLocal, однако, другой поток может возобновить приостановленные сделки, зависит от реализации вашего TransactionManager (я говорю о JBossTransactionManager)

+1

Здесь он использует локальные транзакции, как показано вызовом em.getTransaction(). И в этом случае на EM есть только 1 транзакция, и его дизайн ошибочен. – DataNucleus

5

Использование ThreadLocal переменных для транзакции.

Смотрите также документацию для UserTransaction:

начать()
Создать новую транзакцию и связать его с текущим потоком.

Вы не должны делиться EntityManager, хотя, как гарантируется, он не защищен потоками.

Однако, если вы впрыскиванием в EJB, вам не придется беспокоиться о безопасности потоков: http://www.adam-bien.com/roller/abien/entry/is_in_an_ejb_injected

Если вы используете Spring, чтобы ввести его, вы получите поточно-прокси: http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/orm.html#orm-jpa-straight

Хотя экземпляры EntityManagerFactory являются потокобезопасными, экземпляры EntityManager не являются. Инъецируемый JPA EntityManager ведет себя как EntityManager, извлеченный из среды JNDI сервера приложений, как определено спецификацией JPA. Он делегирует все вызовы текущему транзакционному EntityManager, если таковые имеются; в противном случае он возвращается к вновь созданному EntityManager за операцию, фактически делая его использование потокобезопасным.

+1

Это не правда, по крайней мере, для свежих реализаций Hibernate.Зачем использовать ThreadLocal в объекте, который может использоваться только из одного потока? –

+1

Кажется, что это зависит от того, где вы его используете: http://stackoverflow.com/questions/8603478/does-jboss-handle-managed-entity-manager-concurrency-issues-for-me – Sandro

+0

Нет, инъекция сама по себе не делает один экземпляр потокового менеджера объектов. Вместо этого последовательный доступ к провайдеру ejb по контейнеру гарантирует, что он не используется одновременно из нескольких потоков. Вы также можете использовать jndi lookup вместо инъекции и гарантировать безопасность потока по контракту ejb. –

Смежные вопросы