2010-09-29 12 views
9

Angenommen, Sie verwenden JPA mit Spring, mit Hibernate als JPA-Implementierung. JPA-Transaktionsmodus ist "JTA", daher müssen Sie den Container transactionManager an Hibernate übergeben. Die klassische Antwort lautet hibernate.transaction.manager_lookup_class auf die passende Klasse für Ihren Server.Verwenden von Spring transactionManager in JPA/Hibernate

Allerdings ist es eine Schande, dass dies abhängig von der serverspezifischen Konfiguration ist, da Sie bereits den transactionManager im Frühjahr mit <tx:jta-transaction-manager> gefunden haben.

Gibt es eine Möglichkeit, diese zu geben transaction mit einer Konfiguration Hibernate wie

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

Das Ziel ist die org.hibernate.transaction.SunONETransactionManagerLookup Eigenschaft loszuwerden. Übrigens habe ich wirklich zwei verschiedene Serverimplementierungen im Hinterkopf.

EDIT: ohne die Transaktions-Manager-Konfiguration, Drosseln Hibernate, wenn die EntityManagerFactory erstellen:

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 

Antwort

1

Leider, wenn man sich die Hibernate-APIs wie viele andere JBoss-Produkte anschaut, haben sie eine a-Klasse, die normalerweise Konfiguration genannt wird, um die meisten, wenn nicht alle Hauptkonfigurations-Sachen zu halten. Leider scheinen sie (JBoss) "Strings" für Parameter und Klassen zu haben, um Instanzen zu finden. Fast immer ist es oft unmöglich, ein vorgefertigtes Setup zu erstellen.

Ich bin dabei, aus dem gleichen Grund, den Sie erwähnen, etwas Ähnliches wie das Folgende zu versuchen.

  • Eine Implementierung von TransactionManagerLookup
  • umfassen eine setter der ein TM und stellt einen Thread lokalen Variable + Beispiel nimmt.
  • übergeben Sie den Namen von TML innerhalb der Eigenschaften, die Sie an die Konfiguration übergeben.
  • Wenn Ihr TML startet, kopieren Sie die lokale Thread-Variable in Ihre Instanz fie.d.
  • löschen Sie das Threadlocal, sobald alles fertig ist.
+0

OK, danke, ich nehme an, die richtige Antwort wäre, einen Fehler für Hibernate zu öffnen, da die Konfigurierbarkeit auf ihrer Seite einen Fehler verursacht. – mleduque

0

habe ich kürzlich ein paar Sachen mit JPA/Grails und die Konfiguration Ich war in dieser Richtung verwendet tun:

Hilft das überhaupt?

<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

Nun, Sie können nicht wirklich das gleiche mit JTA tun. – mleduque

5

Zunächst einmal - tun Sie wirklich JTA brauchen? Normalerweise benötigen Frühling + Winterschlaf es nicht. Sie können eine einfache JpaTransactionManager/HibernateTransactionManager verwenden.

Wenn Sie wirklich JTA wollen, dann brauchen Sie einen JTA Provider. Wenn Sie nicht auf einem Anwendungsserver ausgeführt werden, überprüfen Sie this question für die Verwendung von JTA in einem Servlet-Container. (Werfen Sie auch einen Blick auf this question)

Schließlich hibernate docs, die angeben, für Container-gesteuerten Transaktionen:

deklarative Transaktionsabgrenzung ist eine Standardfunktion von EJB, auch bekannt als Container-gesteuerten Transaktionen (CMT) . In EJB 2.x würden Sie XML-Implementierungsdeskriptoren verwenden, um Ihre Transaktionsassembly zu erstellen. In EJB 3.x können Sie JDK 5.0-Annotationsmetadaten direkt in Ihrem Quellcode verwenden, eine viel weniger ausführliche Methode. CMT Transaktionsdemarkation für EJBs in Hibernate-Konfiguration zu aktivieren:

  • gesetzt hibernate.transaction.manager_lookup_class zu einer Lookup-Strategie für Ihr JEE Container
  • hibernate.transaction.factory_class auf org.hibernate.transaction.CMTTransactionFactory

Der zweite Punkt ist vielleicht etwas, das man‘ verpasst haben?

Was die Dokumentation dazu sagt (der nächste Abschnitt) ist, dass, wenn Sie deklarative Transaktion wollen, Winterschlaf ist nicht, wo Sie suchen sollten. Sie müssten einen Interzeptor erstellen. Genau das sind die Feder-Transaktionsmanager. Und das wäre meine Wahl angesichts Ihres Technologie-Stacks (Spring).

Wenn Sie sich nicht auf einen einzelnen JTA-Provider verlassen möchten, erstellen Sie zwei Builds.Zum Beispiel hat maven "maven profiles", die es erlauben, Builds für verschiedene Umgebungen zu erstellen.

+0

Ja, JTA ist erforderlich. Ich frage mich, warum Leute immer annehmen, dass es möglich ist, eine Frage zu beantworten, indem man eines der Elemente auslässt. Für "lookup_class" und "factory_class" habe ich diesen Teil nicht vermisst, aber ich * muss * nicht von dem verwendeten JEE-Container abhängig sein, die Anwendung soll auf (mindestens) zwei verschiedenen Anwendungsservern bereitgestellt werden. – mleduque

+0

@Mleduque Menschen mit einem breiteren Blick auf Technologie übernehmen einige Dinge aufgrund ihrer Erfahrung. Zum Beispiel habe ich selten eine Frühlings-App mit JTA gesehen, während ich viele Fälle gesehen habe, in denen Leute sich hineinwerfen, ohne sie wirklich zu brauchen. Für den Rest deines Kommentars - siehe mein Update. – Bozho

+0

Warum würde jemand die Spring TM -Schicht verwenden ... es tut nichts, nur eine andere Schicht mit anderen Methodennamen und fügt keine neue oder bessere Funktionalität über JTA hinzu. Am Ende wird es eine JNDI-Suche machen (wenn man das JTA-Impl benutzt), die im selben Problem von magischen Strings und Singletons endet. –

Verwandte Themen