Announcement Announcement Module
Collapse
No announcement yet.
using getSession() instead of hibernateTemplate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    You are correct, the config is more complex than usual.
    A combination of legacy code and being embedded within another framework.

    The Data objects are [http]Session stateful; so we make one as each user logs in; hence the prototype.
    And because we pass an argument to the prototype, we use a static factory method.
    That is just to explain the stacktrace, i don't believe that is effecting the AoP/TransactionIntercepter.
    [The other 'complexity' you may notice is injecting the txManager to sessionData;
    that is for my next question about controlling commits... but is not used/impacting the current scenario]

    And yes, Data implements (a couple of) Interfaces, and again, that part is working;
    as is apparent when we get the correct Session, transactions are auto-created and auto-closed.

    Is there a reason that the LocalSessionFactoryBean would be confused in face of a prototype object?
    As you see, the TransactionInterceptor appear to be there...

    Given the correct value from 'getSession()' everything works.
    So, how do we get the correct value from getSession without ServerFactoryUtils?

    Without yet looking at the source for LocalSessionFactoryBean, i wonder about this:
    Other parts of the code (the UserDetailsService that is calling newData) still use native Hibernate,
    so there is probably a ThreadLocal or Session-bound native Hibernate Session lurking...
    Could *that* be what is interfering??
    Last edited by Jack Punt; Apr 17th, 2009, 06:37 PM. Reason: clarify text

    Comment


    • #17
      To reduce the complexity/confusion, i've reduced it to a simple test case.
      This is the entire code; no app server, no other framework.
      Just this class in an interpreter that invokes:
      Code:
       appctx = ClassPathXmlApplicationContext( "project-test.xml" );
       testbean = appctx.getBean("test");
       testbean.doTest(true);   // sf.getSession()
       testbean.doTest(false);  // sessionFactoryUtils.getSession(sf, false)
       testbean.doTest(true);
      The code:
      Code:
      package com.local.data; // Generated package name
      
      public interface ITest {
      	public Object getTest(boolean flag);
      	public Object doTest(boolean flag);
      }
      package com.local.data;
      
      import org.hibernate.Session;
      import org.hibernate.SessionFactory;
      import org.springframework.orm.hibernate3.SessionFactoryUtils;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      public class TestTrans implements ITest {
      	// Spring setter: (for Hibernate 3.1 DAO pattern)
      	public void setSessionFactory(SessionFactory sf) { this.sessionFactory = sf; }
      	private SessionFactory sessionFactory;
      
      	public Session getSession1() { return sessionFactory.getCurrentSession(); }
      	public Session getSession2() { return SessionFactoryUtils.getSession(sessionFactory, false);}
      	public Session getSession()  { return getSession2(); }
      
      	public Object getTest(boolean flag) {
      		Session rv = flag? getSession1() : getSession2();
      		System.out.printf("session=@%x: %s \n",System.identityHashCode(rv),rv);
      		rv.createQuery("from User");
      		return rv;
      	}
      	public Object doTest(boolean flag)  {
      		Session rv = flag? getSession1() : getSession2();
      		System.out.printf("session=@%x: %s \n",System.identityHashCode(rv),rv);
      		rv.createQuery("from User");
      		return rv;
      	}
      }
      The config (project-trans.xml):
      Code:
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-2.5.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.5.xsd
      "
      xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:sec="http://www.springframework.org/schema/security"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:tx="http://www.springframework.org/schema/tx"
      xmlns:context="http://www.springframework.org/schema/context"
      >
      
          <!-- Based on Chapter 9; and DAO (Data/UserData) extends HibernateDaoSupport. -->
      
          <!-- Hibernate local transactions: -->
          <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
              <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>
              <property name="configLocations">
                  <list>
                  <value>classpath:customerdb.cfg.xml</value>
                  <value>classpath:generic.cfg.xml</value>
                  </list>
              </property>
          </bean>
      
          <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
              <property name="sessionFactory" ref="sessionFactory" />
          </bean>
      
        <!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
        <tx:advice id="txAdvice" transaction-manager="txManager">
          <!-- the transactional semantics... -->
          <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*"/>
          </tx:attributes>
        </tx:advice>
        
        <!-- ensure that the above transactional advice runs for any execution
            of an operation defined by the FooService interface -->
        <aop:config>
          <aop:pointcut id="itest" expression="execution(public * com.local.data.ITest.*(..))"/>
          <aop:advisor advice-ref="txAdvice" pointcut-ref="itest"/>
        </aop:config>
      
        <bean id="test" class="com.local.data.TestTrans">
          <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
      
      </beans>
      The results (my apologies for the scheme syntax... the java-based interpreter pre-dates beanshell)
      Code:
      Fri Apr 17 16:33:21 PDT 2009
      -> (initAppCtx "project-test.xml")
      org.springframework.context.support.ClassPathXmlApplicationContext@1af33d6: 
      display name [org.springframework.context.support.ClassPathXmlApplicationContext@1af33d6];
      startup date [Fri Apr 17 16:33:25 PDT 2009]; root of context hierarchy
      -> (define testbean (appctx.getBean. "test"))
      com.local.data.TestTrans@148bd9d
      -> (testbean.doTest. #!true)
      session=@8a1f38: SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];
      ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[]]) 
      org.hibernate.HibernateException: createQuery is not valid without active transaction
      Eval: (testbean.doTest. true)
      Invo: ($Proxy19.doTest com.local.data.TestTrans@148bd9d true)
      TopLevel: createQuery is not valid without active transaction
      -> (testbean.doTest. #!false)
      session=@10e8647: SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];
      ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[]]) 
      SessionImpl(<closed>)
      -> (testbean.doTest. #!true)
      session=@8a1f38: SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];
      ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[]]) 
      org.hibernate.HibernateException: createQuery is not valid without active transaction
      Eval: (huds.doTest. true)
      Invo: ($Proxy19.doTest com.local.data.TestTrans@148bd9d true)
      TopLevel: createQuery is not valid without active transaction
      -> (showStackTrace)
      org.hibernate.HibernateException: createQuery is not valid without active transaction
      	at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:297)
      	at $Proxy21.createQuery(Unknown Source)
      	at com.local.data.TestTrans.doTest(TestTrans.java:28)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at java.lang.reflect.Method.invoke(Method.java:585)
      	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
      	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
      	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
      	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
      	at $Proxy19.doTest(Unknown Source)
      
      ->
      As you can see; the TransactionInterceptor is working fine with "false": getSession2()
      but it not creating/closing any transaction for "true" : getSession1();
      The proxy is there, but it is working on different Sessions.
      We see that getSession1() continues to return the same Session...

      Comment


      • #18
        post your 2 cfg.xml files. There must be something wrong with your configuration....

        Comment


        • #19
          Marten, thank you for looking in to this.
          The database configuration, FWIW:

          customerdb.cfg.xml
          Code:
          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
          <hibernate-configuration>
              <session-factory>
                  <property name="hibernate.c3p0.idle_test_period">3600</property>
                  <property name="hibernate.c3p0.max_size">20</property>
                  <property name="hibernate.c3p0.max_statements">50</property>
                  <property name="hibernate.c3p0.min_size">0</property>
                  <property name="hibernate.c3p0.timeout">7200</property>
                  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
                  <property name="hibernate.connection.password">*********</property>
                  <property name="hibernate.connection.url">jdbc:mysql://mysql_host/customerdb</property>
                  <property name="hibernate.connection.username">*********</property>
                  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
                  <property name="hibernate.format_sql">true</property>
                  <property name="hibernate.show_sql">true</property>
                  <mapping class="com.local.data.customerdb.User" />
                  <!-- more classes/tables in the real thing -->
              </session-factory>
          </hibernate-configuration>
          generic.cfg.xml
          Code:
          <?xml version='1.0' encoding='utf-8'?>
          <!DOCTYPE hibernate-configuration PUBLIC
          		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          		"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
          <hibernate-configuration>
          	<session-factory>
          		<!-- Enable Hibernate's automatic session context management -->
          		<property name="current_session_context_class">thread</property>
          		<!-- Disable the second-level cache	 -->
          		<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
                  <property name="hibernate.format_sql">false</property>
                  <property name="hibernate.show_sql">false</property>
          	</session-factory>
          </hibernate-configuration>
          Please confirm: we are not using/expecting HibernateTransactionManager.hibernateManagedSessio n=true

          I stepped through the code, and notice that Spring's HibernateTransactionManager (v2.5.5) eventually does this:
          Code:
              // Bind the session holder to the thread.
              if (txObject.isNewSessionHolder()) {
                 TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
          Which is where Spring's SessionFactoryUtils.getSession(..) finds the SessionHolder and Session.
          But Hibernate's SessionFactoryImpl.getCurrentSession() is looking for a CurrentSessionContext object
          [which the Spring code does not seem to coordinate with. ]

          By the way, I have: Hibernate-Version: 3.2.4.sp1 (with Spring 2.5.4 and now 2.5.5)
          Is there some other version where Spring and Hibernate actually agree on where and how to do Thread-bound Session?

          Comment


          • #20
            Tread setting

            In this your concrete case I see only one point in your configuration that may cause the problem. Actually it is <property name="current_session_context_class">thread</property> remove it at all.

            But the strangest thing it did not help me even though I have similar configuration you have already seen so I start wandering if I need to recover the old code there all data managers inherited from HibernateDaoSupport.

            Comment


            • #21
              Firebrick,
              I don't know where that property came from...
              But you are right! removing that, the transaction management works!
              (some hibernate example from way back, i suppose; but debunked here)

              I hope that encourages you to find the solution to your problem.

              Thank you (and Marten, whom I'm sure will also spot that problem when the sun again rises in Netherland)
              Last edited by Jack Punt; Apr 18th, 2009, 05:33 PM.

              Comment


              • #22
                Well the sun rose about 2 hours ago here . Indeed I spotted the culprit (as I already suspected that is why I asked for your configuration files).

                Good luck in further migrating and completing your application.

                Comment

                Working...
                X