2010-09-29 20 views
9

Supponiamo di utilizzare JPA con Spring, con Hibernate come implementazione JPA. La modalità di transazione JPA è "JTA", quindi è necessario passare il contenitore transactionManager a Hibernate. La risposta classica è impostare hibernate.transaction.manager_lookup_class sulla classe corrispondente per il proprio server.Utilizzo di transactionManager definito in primavera in JPA/Hibernate

Tuttavia, penso che sia una vergogna dipendere da una configurazione specifica del server come già trovato in transactionManager in primavera con <tx:jta-transaction-manager>.

C'è un modo per dare a questo transactionManager di Hibernate con una configurazione come

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

L'obiettivo è quello di sbarazzarsi della proprietà org.hibernate.transaction.SunONETransactionManagerLookup. A proposito, ho in mente due implementazioni di server differenti.

EDIT: senza la configurazione del gestore delle transazioni, Hibernate soffoca durante la creazione del 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 

risposta

1

Sfortunatamente se si guardano le API di Hibernate come molti altri prodotti di JBoss, hanno una classe tipicamente chiamata Configurazione per contenere la maggior parte, se non tutte le principali cose di configurazione. Sfortunatamente loro (JBoss) sembrano voler tenere "Strings" per i parametri e class per individuare le istanze. Quasi sempre è spesso impossibile impostare semplicemente un premade effettivo pronto per l'installazione.

Sto per provare qualcosa di simile al seguente per la stessa ragione per cui lei sta citando.

  • Creare un'implementazione di TransactionManagerLookup
  • includono un setter che prende una MT e imposta un filo variabile locale + esempio.
  • passare il nome di TML all'interno delle proprietà passate alla configurazione.
  • All'avvio di TML, copiare la variabile locale del thread nell'istanza fie.d.
  • cancellare il threadlocal una volta che tutto è stato fatto.
+0

OK, grazie, suppongo che il giusto analista sarebbe quello di aprire un bug per Hibernate, in quanto è la configurabilità dalla loro parte che è in difetto. – mleduque

0

Recentemente ho fatto alcune cose con JPA/Grails e la configurazione che ho usato era in queste righe:

Questo aiuta a tutti?

<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

Beh, non puoi davvero fare la stessa cosa con JTA. – mleduque

5

Prima di tutto - si fa davvero bisogno JTA? In genere primavera + ibernazione non lo richiedono. È possibile utilizzare un semplice JpaTransactionManager/HibernateTransactionManager.

Se si desidera realmente JTA, quindi è necessario un provider JTA. Se non è in esecuzione in un server applicazioni, selezionare this question per informazioni sull'utilizzo di JTA in un contenitore servlet. (Anche dare un'occhiata al this question)

Infine, hibernate docs precisano che, per le transazioni gestite dal contenitore:

demarcazione dichiarativa delle transazioni è una caratteristica standard di EJB, noto anche come transazioni gestite dal contenitore (CMT) . In EJB 2.x si utilizzano i descrittori di distribuzione XML per creare l'assembly della transazione. In EJB 3.x è possibile utilizzare i metadati di annotazione JDK 5.0 direttamente nel codice sorgente, un approccio molto meno dettagliato. Per abilitare CMT demarcazione transazione per EJB in configurazione di Hibernate:

  • impostato hibernate.transaction.manager_lookup_class ad una strategia di ricerca per il vostro contenitore JEE
  • impostato hibernate.transaction.factory_class a org.hibernate.transaction.CMTTransactionFactory

Il secondo punto è forse qualcosa che si' hai perso?

Ciò che la documentazione dice in aggiunta a questo (la sezione successiva) è che se si desidera una transazione dichiarativa, la sospensione non è dove si dovrebbe guardare. Dovresti creare un intercettore. Questo è esattamente ciò che sono i gestori delle transazioni primaverili. E quella sarebbe la mia scelta dato il tuo stack tecnologico (primavera).

Se si desidera non fare affidamento su un singolo provider JTA, quindi creare due build.Ad esempio, maven ha "profili maven", che consentono di creare build per ambienti diversi.

+0

Sì, è necessario JTA. Mi chiedo perché la gente supponga sempre che sia possibile rispondere a una domanda omettendo uno degli elementi. Per 'lookup_class' e 'factory_class', non ho perso quella parte, ma I * non * deve essere dipendente dal contenitore JEE che viene utilizzato, l'applicazione deve essere distribuita su (almeno) due diversi application server. – mleduque

+0

@mleduque persone con una visione più ampia della tecnologia assumono alcune cose a causa della loro esperienza. Ad esempio, raramente ho visto un'app di primavera con JTA, mentre ho visto molti casi in cui la gente ci si butta dentro senza realmente averne bisogno. Per il resto del tuo commento - guarda il mio aggiornamento. – Bozho

+0

perché qualcuno dovrebbe usare il livello Spring TM ... non fa nulla è solo un altro livello con nomi di metodi diversi e non aggiunge nuove o migliori funzionalità su JTA. Alla fine farà una ricerca jndi (se si usa l'impl JTA) che finisce nello stesso problema delle stringhe magiche e dei singleton. –

Problemi correlati