在 JPA/Hibernate 中使用 Spring 定义的 transactionManager

发布于 2024-09-25 05:25:37 字数 4915 浏览 6 评论 0原文

假设您将 JPA 与 Spring 结合使用,并使用 Hibernate 作为 JPA 实现。 JPA事务模式是“JTA”,因此需要将容器transactionManager传递给Hibernate。 经典的答案是将 hibernate.transaction.manager_lookup_class 设置为服务器的匹配类。

但是,我认为这种依赖于服务器特定配置的行为是一种耻辱,因为您已经在 Spring 中使用 找到了 transactionManager。

有没有办法通过类似的配置将此 transactionManager 提供给 Hibernate

 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="persistence_unit_name"/>
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
  </property>
  <property name="jpaProperties">
   <props>
    <prop key="hibernate.transaction.manager_lookup_class">
     org.hibernate.transaction.SunONETransactionManagerLookup
    </prop>
   </props>
  </property>
 </bean>

 <tx:jta-transaction-manager/>

目标是摆脱 org.hibernate.transaction.SunONETransactionManagerLookup 属性。 顺便说一句,我确实有两种不同的服务器实现。

编辑:如果没有事务管理器配置,Hibernate 在创建 EntityManagerFactory 时会阻塞:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in URL [file:/C:/configuration/afoCuad-metier-ear/entitymanager-base-context.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: fr.tm.ima.cuad-afoCuad-metier-ejb-PU] Unable to build EntityManagerFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:529)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:495)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:656)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:629)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:147)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:338)
... 80 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: fr.tm.ima.cuad-afoCuad-metier-ejb-PU] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:901)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:308)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 93 more
Caused by: org.hibernate.HibernateException: The chosen transaction strategy requires access to the JTA TransactionManager
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:401)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:892)
... 98 more

Suppose you use JPA with Spring, with Hibernate as JPA implementation.
JPA transaction mode is "JTA", so you need to pass the container transactionManager to Hibernate.
The classical answer is to set hibernate.transaction.manager_lookup_class to the matching class for your server.

However, I think it's a shame to have this depend of server specific configuration as you already found the transactionManager in Spring with <tx:jta-transaction-manager>.

Is there a way to give this transactionManager to Hibernate with a configuration like

 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="persistence_unit_name"/>
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
  </property>
  <property name="jpaProperties">
   <props>
    <prop key="hibernate.transaction.manager_lookup_class">
     org.hibernate.transaction.SunONETransactionManagerLookup
    </prop>
   </props>
  </property>
 </bean>

 <tx:jta-transaction-manager/>

The goal is to get rid of the org.hibernate.transaction.SunONETransactionManagerLookup property.
By the way, I really have two different server implementations in mind.

EDIT : without the transaction manager configuration, Hibernate chokes when creating the EntityManagerFactory :

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in URL [file:/C:/configuration/afoCuad-metier-ear/entitymanager-base-context.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: fr.tm.ima.cuad-afoCuad-metier-ejb-PU] Unable to build EntityManagerFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:529)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:495)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:656)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:629)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:147)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:338)
... 80 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: fr.tm.ima.cuad-afoCuad-metier-ejb-PU] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:901)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:308)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 93 more
Caused by: org.hibernate.HibernateException: The chosen transaction strategy requires access to the JTA TransactionManager
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:401)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:892)
... 98 more

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风轻花落早 2024-10-02 05:25:37

首先 - 您真的需要JTA吗?通常 spring+hibernate 不需要它。您可以使用简单的JpaTransactionManager / HibernateTransactionManager

如果您确实想要 JTA,那么您将需要 JTA 提供者。如果未在应用程序服务器中运行,请检查此问题< /a> 了解如何在 servlet 容器中使用 JTA。 (另请查看这个问题

最后,hibernate 文档 指定,对于容器管理的事务:

声明式事务划分是 EJB 的一项标准功能,也称为容器管理事务 (CMT)。在 EJB 2.x 中,您将使用 XML 部署描述符来创建事务程序集。在 EJB 3.x 中,您可以直接在源代码中使用 JDK 5.0 注释元数据,这是一种更简洁的方法。要在 Hibernate 配置中为 EJB 启用 CMT 事务划分:

  • hibernate.transaction.manager_lookup_class 设置为 JEE 容器的查找策略
  • hibernate.transaction.factory_class设置为org.hibernate.transaction.CMTTransactionFactory

第二点也许是您错过的?

除此之外(下一节)文档还说,如果您想要声明式事务,那么 hibernate 不是您应该考虑的地方。您需要创建一个拦截器。这正是 Spring 事务管理器的本质。考虑到您的技术堆栈(Spring),这将是我的选择。

如果您不希望依赖单个 JTA 提供程序,请进行两个构建。例如,maven 有“maven 配置文件”,它允许为不同的环境进行构建。

First of all - do you really need JTA? Typically spring+hibernate don't require it. You can use a simple JpaTransactionManager / HibernateTransactionManager.

If you really want JTA, then you will need a JTA provider. If not running in an application server, check this question for how to use JTA in a servlet container. (Also take a look at this question)

Finally, hibernate docs specify that, for container-managed transactions:

Declarative transaction demarcation is a standard feature of EJB, also known as container-managed transactions (CMT). In EJB 2.x you would use XML deployment descriptors to create your transaction assembly. In EJB 3.x you can use JDK 5.0 annotation metadata directly in your source code, a much less verbose approach. To enable CMT transaction demarcation for EJBs in Hibernate configuration:

  • set hibernate.transaction.manager_lookup_class to a lookup strategy for your JEE container
  • set hibernate.transaction.factory_class to org.hibernate.transaction.CMTTransactionFactory

The second point is perhaps something you've missed?

What the documentation says in addition to that (the next section) is that if you want declarative transaction, hibernate is not where you should look at. You'd need to create an interceptor. That's exactly what spring transaction managers are. And that would be my choice given your technology stack (Spring).

If you wish not to rely on a single JTA provider, then make two builds. For example maven has "maven profiles", which allow to make builds for different environments.

追星践月 2024-10-02 05:25:37

不幸的是,如果你像许多其他 JBoss 产品一样看待 Hibernate API,他们有一个通常称为 Configuration 的类来保存大多数(如果不是全部)主要配置内容。不幸的是,他们(JBoss)似乎喜欢保存参数和类的“字符串”来定位实例。几乎总是不可能简单地设置实际的预制准备就绪设置。

出于与您提到的相同原因,我将尝试类似于以下内容的操作。

  • 创建 TransactionManagerLookup 的实现,
  • 包括一个 setter,它采用 TM 并设置线程局部变量 + 实例。
  • 在传递给配置的属性中传递 TML 名称。
  • 当您的 TML 启动时,将线程局部变量复制到您的实例 fie.d。
  • 一切完成后清除线程本地。

Unfortunately if one looks at the Hibernate APIs like many other JBoss products they have a a class typically called Configuration to hold most if not all the main config stuff. Unfortunately they (JBoss) seem to like to hold "Strings" for parameters and class to locate instances. Almost always its often impossible to simply set an actual premade ready to go setup.

I am about to try something similar to the following for the very same reason you are mentioning.

  • Create an implementation of TransactionManagerLookup
  • include a setter which takes a TM and sets a thread local variable + instance.
  • pass the name of TML inside the properties you pass to the Configuration.
  • When Your TML startsup copy the thread local variable to your instance fie.d.
  • clear the threadlocal once everything is done.
层林尽染 2024-10-02 05:25:37

我最近一直在使用 JPA/Grails 做一些事情,我使用的配置是这样的:

这有帮助吗?

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.hibernate.ejb.EntityManagerFactoryImpl">
 <constructor-arg index="0" ref="sessionFactory"/>
 <constructor-arg index="1">
   <bean id="javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
 </constructor-arg>
 <constructor-arg index="2" value="true"/>
 <constructor-arg index="3"><null/></constructor-arg>
</bean>

I've recently been doing some stuff with JPA/Grails and the configuration I used was along these lines:

Does this help at all?

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.hibernate.ejb.EntityManagerFactoryImpl">
 <constructor-arg index="0" ref="sessionFactory"/>
 <constructor-arg index="1">
   <bean id="javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
 </constructor-arg>
 <constructor-arg index="2" value="true"/>
 <constructor-arg index="3"><null/></constructor-arg>
</bean>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文