2010-09-29 23 views
9

Supongamos que utiliza JPA con Spring, con Hibernate como implementación de JPA. El modo de transacción JPA es "JTA", por lo que debe pasar el contenedor transactionManager para Hibernar. La respuesta clásica es establecer hibernate.transaction.manager_lookup_class en la clase coincidente para su servidor.Uso de Spring defined transactionManager en JPA/Hibernate

Sin embargo, creo que es una pena que esto dependa de la configuración específica del servidor, ya que usted encontró el transactionManager en Spring con <tx:jta-transaction-manager>.

¿Hay una manera de dar a este transactionManager a Hibernate con una configuración como

<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/> 

El objetivo es deshacerse de la propiedad org.hibernate.transaction.SunONETransactionManagerLookup. Por cierto, realmente tengo dos implementaciones de servidores diferentes en mente.

EDIT: sin la configuración del gestor de transacciones, Hibernate ahoga al crear el 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 

Respuesta

1

Desafortunadamente, si uno mira las API de Hibernate como muchos otros productos de JBoss, tienen una clase que normalmente se llama Configuración para contener la mayoría, si no todas las cosas de la configuración principal. Desafortunadamente, a ellos (JBoss) parece gustarles tener "Cadenas" para parámetros y clases para localizar instancias. Casi siempre es imposible simplemente establecer una configuración preinstalada real.

Estoy a punto de intentar algo similar a lo siguiente por el mismo motivo que usted menciona.

  • Crear una implementación de TransactionManagerLookup
  • incluyen un setter que tiene un TM y establece una variable local hilo + instancia.
  • pase el nombre de TML dentro de las propiedades que pasa a la Configuración.
  • Cuando su TML se inicia, copie la variable local del hilo a su instancia fie.d.
  • borre el threadlocal una vez que todo esté hecho.
+0

Bien, gracias, supongo que lo correcto sería abrir un error para Hibernate, ya que es la capacidad de configuración de su parte la culpable. – mleduque

0

Recientemente he estado haciendo algunas cosas con APP/Grails y la configuración que utilicé fue a lo largo de estas líneas:

¿Esto ayuda en absoluto?

<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> 
+0

Bueno, en realidad no se puede hacer lo mismo con JTA. – mleduque

5

En primer lugar - que realmente necesitan JTA? Por lo general, spring + hibernate no lo requieren. Puede usar un simple JpaTransactionManager/HibernateTransactionManager.

Si realmente quieres JTA, necesitarás un proveedor de JTA. Si no se está ejecutando en un servidor de aplicaciones, verifique this question para saber cómo usar JTA en un contenedor de servlets. (También echa un vistazo a this question)

Por último, hibernate docs precisar que para las transacciones gestionadas por contenedor:

demarcación de transacciones declarativa es una característica estándar de EJB, también conocido como transacciones gestionadas por contenedor (CMT) . En EJB 2.x usaría los descriptores de despliegue XML para crear su ensamblado de transacción. En EJB 3.x puede usar metadatos de anotación JDK 5.0 directamente en su código fuente, un enfoque mucho menos detallado. Para habilitar la demarcación de transacción CMT para EJB en configuración de Hibernate:

  • conjunto hibernate.transaction.manager_lookup_class a una estrategia de búsqueda para su contenedor JEE
  • establece hibernate.transaction.factory_class a org.hibernate.transaction.CMTTransactionFactory

El segundo punto es quizás algo que' ¿Has perdido?

Lo que la documentación dice además de eso (la siguiente sección) es que si quieres una transacción declarativa, hibernar no está donde deberías mirar. Necesitarías crear un interceptor. Eso es exactamente lo que los gerentes de transacciones de primavera son. Y esa sería mi elección dada su pila de tecnología (Spring).

Si no desea confiar en un único proveedor de JTA, realice dos compilaciones.Por ejemplo, maven tiene "perfiles de maven", que permiten construir para diferentes entornos.

+0

Sí, se requiere JTA. Me pregunto por qué las personas siempre suponen que es posible responder una pregunta omitiendo uno de los elementos. Para 'lookup_class' y 'factory_class', no me perdí esa parte, pero * no * debo depender del contenedor JEE que se utiliza, la aplicación se implementará en (al menos) dos servidores de aplicaciones diferentes. – mleduque

+0

@mleduque personas con una visión más amplia de la tecnología asumen algunas cosas debido a su experiencia. Por ejemplo, rara vez he visto una aplicación de primavera con JTA, mientras que he visto muchos casos en que las personas se arrojan sin necesidad de hacerlo. Para el resto de tu comentario, mira mi actualización. – Bozho

+0

por qué alguien usaría la capa Spring TM ... no hace nada es solo otra capa con diferentes nombres de métodos y no agrega ninguna funcionalidad nueva o mejor sobre JTA. Al final va a hacer una búsqueda jndi (si uno usa la impl JTA) que termina en el mismo problema de cadenas mágicas y singletons. –

Cuestiones relacionadas