Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Java/Spring/Hibernate] No Hibernate Session bound to thread

Pagina: 1
Acties:

  • rrrandy
  • Registratie: Juli 2005
  • Laatst online: 27-06 13:00
De volledige foutmelding pastte niet in de titel en luidt:
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Mijn situatie is redelijk 'complex', ik probeer drie application contexts van drie applicaties samen te voegen en transactiemanagement toe te passen over de database verbindingen van alle drie de applicaties. In theorie kunnen de applicaties drie verschillende databases aanspreken.

Dat gaat zo:

applicationContext.xml van de hoofdapplicatie:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
    <bean id="app.context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg>
            <list>
                <value>applicationContext-app.xml</value>
                <value>applicationContext-app1.xml</value>
                <value>applicationContext-app2.xml</value>
                <value>applicationContext-app3.xml</value>
            </list>
        </constructor-arg>
    </bean>
</beans>


De applicationContext-app.xml definieert de jotm jta transactionmanager:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
    
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="userTransaction">
            <ref local="jotm"/>
        </property>
    </bean>
    
    <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
    
    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributeSource">
            <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
        </property>
    </bean>

    <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor" ref="transactionInterceptor"/>
    </bean>
</beans>


App 1 t/m 3 stellen de drie applicaties voor die ik samen wil voegen. Het relevante deel uit 1 van de applicationContexts:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
    
    <bean id="app1InnerDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
       <property name="transactionManager" ref="jotm"/>
       <property name="driverName"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/driver"/></property>
       <property name="url"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/url"/></property>
       <property name="maxCon"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/maxCon"/></property>
       <property name="minCon"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/minCon"/></property>
    </bean>

    <bean id="app1DataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
      <property name="dataSource" ref="app1InnerDataSource"/>
      <property name="user"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/username"/></property>
      <property name="password"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/password"/></property>
      <property name="maxSize"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/maxPoolSize"/></property>
      <property name="minSize"><jee:jndi-lookup jndi-name="java:comp/env/app1/jdbc/minPoolSize"/></property>
    </bean>
    
    <bean id="app1HibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="configLocation">
            <value>classpath:hibernate.app1.cfg.xml</value>
        </property>
        <property name="schemaUpdate">
            <value>false</value>
        </property>
        <property name="dataSource" ref="app1DataSource"/>
    </bean>
    
    <bean id="app1HibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory"><ref bean="app1HibernateSessionFactory"/></property> 
        <property name="jdbcExceptionTranslator"><ref bean="app1JdbcExceptionTranslator"/></property> 
    </bean>
    
    <bean id="app1JdbcExceptionTranslator" class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator"> 
        <property name="dataSource"><ref bean="app1DataSource"/></property> 
    </bean>
    
    <bean id="app1JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
        <property name="dataSource"><ref bean="app1DataSource"/></property>
        <property name="exceptionTranslator"><ref bean="app1JdbcExceptionTranslator"/></property> 
    </bean>
</beans>


App2 en App3 zijn vergelijkbaar opgezet.

Wanneer ik de applicatie met Tomcat opstart gaat alles goed, jta wordt geladen en session factories worden gemaakt. Wanneer ik nu via een service in een van mijn apps probeer een hibernate sessie op te halen via:
Java:
1
Session session = getHibernateTemplate().getSessionFactory().getCurrentSession();


waar ik heb gedefinieerd dat:

Java:
1
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)


Dan krijg ik dus bovenstaande melding:
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Moet ik ergens in mijn configuratie expliciet maken dat bepaalde threads bij een bepaalde session factory horen? Moet ik iets bouwen dat bijv. via een threadlocal de juiste factory oplevert? Ik heb aardig wat afgezocht, maar kan niet vinden wat nu exact mijn probleem hier is en nog belangrijker, de oplossing ;)

Spring gurus hier?

  • momania
  • Registratie: Mei 2000
  • Laatst online: 30-11 19:29

momania

iPhone 30! Bam!

In je web.xml kan je voor elke app context een OpenSessionInViewFilter toevoegen.

XML:
1
2
3
4
5
<filter>
    <filter-name>app1hibernateFilter</filter-name>
    <filter-class>com.fortis.nl.gsla.camas.web.CamasOpenSessionInViewFilter</filter-class>
    <init-param>app1HibernateSessionFactory</init-param>
</filter>

Die opent bij elk webrequest een session voor je.

En dan moet je de specifieke filters nog aan de juiste context hangen. (En dan moet je dus wel zorgen dan de verschillende 'applicaties' onder een andere context hangen.

XML:
1
2
3
4
<filter-mapping>
      <filter-name>app1hibernateFilter</filter-name>
      <url-pattern>app1/*</url-pattern>
</filter-mapping>


Weet niet of dit de precieze configuratie zou zijn, want heb het zelf nooit zo gebruikt, maar dat moet je dan maar even zelf verder uitzoeken :)

Voor het laden van je application context files kan je ook een simpele context param toevoegen aan je web.xml
XML:
1
2
3
4
5
6
7
8
9
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:applicationContext-app.xml
        classpath:applicationContext-app1.xml
        classpath:applicationContext-app2.xml
        classpath:applicationContext-app3.xml
    </param-value>
</context-param>

Gebruik hier "classpath*:applicationContext-sub.xml" (met * dus) als de xml file in een andere jar zit dan de web.xml zelf :)

En even een een listener toevoegen:
XML:
1
2
3
4
5
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

[ Voor 32% gewijzigd door momania op 06-08-2007 16:26 ]

Neem je whisky mee, is het te weinig... *zucht*


  • rrrandy
  • Registratie: Juli 2005
  • Laatst online: 27-06 13:00
Tnx voor de reply.

Heb de contexts verplaatst naar de web.xml, dat staat wat beter inderdaad, maar lost het probleem uiteraard niet op.

Kwam er nog wel achter dat in mijn web.xml de OpenSessionInViewFilter verkeerd stond gedefinieerd, alleen voor app1 en niet voor alle drie. Dat heb ik nu aangepast, maar dat haalt niets uit.

  • momania
  • Registratie: Mei 2000
  • Laatst online: 30-11 19:29

momania

iPhone 30! Bam!

En hoe is je filter mapping dan?

Als je mapping niet matched met de request waar je een session nodig hebt, wordt er ook geen session geopend natuurlijk :)

Aangezien je toch met spring 2 bezig bent, kan je volgende mij het volgende:
XML:
1
2
3
4
5
6
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributeSource">
       <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
    </property>
</bean>

... vervangen door:
XML:
1
<tx:annotation-driven/>

... en
XML:
1
xmlns:tx="http://www.springframework.org/schema/tx"

... toe te voegen :)

[ Voor 66% gewijzigd door momania op 06-08-2007 16:50 ]

Neem je whisky mee, is het te weinig... *zucht*


  • rrrandy
  • Registratie: Juli 2005
  • Laatst online: 27-06 13:00
momania schreef op maandag 06 augustus 2007 @ 16:46:
En hoe is je filter mapping dan?

Als je mapping niet matched met de request waar je een session nodig hebt, wordt er ook geen session geopend natuurlijk :)
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
<filter>
        <filter-name>App1OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>sessionFactoryBeanName</param-name>
            <param-value>app1HibernateSessionFactory</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>App1OpenSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


en zo verder voor app2 en app3. Lijkt me toch niks mis mee?

  • momania
  • Registratie: Mei 2000
  • Laatst online: 30-11 19:29

momania

iPhone 30! Bam!

rrrandy schreef op maandag 06 augustus 2007 @ 16:50:
[...]

en zo verder voor app2 en app3. Lijkt me toch niks mis mee?
Je mapped nu alle filters direct op de root. Volgens mij raakt hibernate/spring dan een beetje in de war ;)
Als je 3 verschillende sessionfactories wilt gebruiken, zal je ze alle 3 aan een andere sub webcontext moeten hangen.

Neem je whisky mee, is het te weinig... *zucht*


  • rrrandy
  • Registratie: Juli 2005
  • Laatst online: 27-06 13:00
momania schreef op maandag 06 augustus 2007 @ 16:52:
[...]

Je mapped nu alle filters direct op de root. Volgens mij raakt hibernate/spring dan een beetje in de war ;)
Als je 3 verschillende sessionfactories wilt gebruiken, zal je ze alle 3 aan een andere sub webcontext moeten hangen.
Het is erg warm hier ;)

Je hebt helemaal gelijk. Maar dan nog, mijn probleem blijft...

  • momania
  • Registratie: Mei 2000
  • Laatst online: 30-11 19:29

momania

iPhone 30! Bam!

Ik kom net dit artikel tegen in een Interface21 blog: http://blog.interface21.c...namic-datasource-routing/

Misschien dat dat nog wel een mooiere oplossing is voor je :)

Neem je whisky mee, is het te weinig... *zucht*


  • rrrandy
  • Registratie: Juli 2005
  • Laatst online: 27-06 13:00
momania schreef op maandag 06 augustus 2007 @ 16:58:
Ik kom net dit artikel tegen in een Interface21 blog: http://blog.interface21.c...namic-datasource-routing/

Misschien dat dat nog wel een mooiere oplossing is voor je :)
Goed, als ik dit vluchtig even doorlees gaat deze vlieger alleen op in het geval van homogene datasources. Ik wil transactionmanagement kunnen doen over een connectie naar een Oracle DB, een JMS queue wat RMI methodes en misschien nog wel een MySQL, PostgreSQL of DB2 verbinding. Dan wil ik toch graag een transactionmanager waar ik mijn datasources kan registreren :)

  • momania
  • Registratie: Mei 2000
  • Laatst online: 30-11 19:29

momania

iPhone 30! Bam!

rrrandy schreef op dinsdag 07 augustus 2007 @ 09:05:
[...]


Goed, als ik dit vluchtig even doorlees gaat deze vlieger alleen op in het geval van homogene datasources.
Hmm, true. Ik denk er nog even verder over na. Ik heb het zelf nml. nog niet nodig gehad om meerdere sessionfactories te hebben. Ik ben het verder op blogs, in documentatie, etc ook nog niet tegengekomen. :)

Neem je whisky mee, is het te weinig... *zucht*

Pagina: 1