using current_session_context_class property hiber

2019-02-07 00:28发布

问题:

I have an application with Spring and Hibernate3 running well in production. Following is the config for session factory in Spring's applicationContext.xml

       <bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mappingDirectoryLocations">
        <list>
            <value>classpath:/hibernate</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect
            </prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.use_sql_comments">true</prop>
            <prop key="hibernate.max_fetch_depth">2</prop>
            <prop key="hibernate.autocommit">false</prop>
            <prop key="hibernate.current_session_context_class ">thread</prop>
                            <prop key="hibernate.generate_statistics">true</prop>
            <prop key="hibernate.jdbc.batch_size">20</prop>
        </props>
    </property>
</bean>

<bean id="txManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean 
    below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
        <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="count*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="validate*" propagation="SUPPORTS"
            read-only="true" />
        <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="login" propagation="SUPPORTS" read-only="true" />
    </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution of 
    an operation defined by the service interfaces -->
<aop:config>
    <aop:pointcut id="projectServiceOperation"
        expression="execution(* com.service.project.IProjectService.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="projectServiceOperation" />
</aop:config>

It is working fine in production.

Now for another project we are migrating to Hibernate4. we copied over the same configuration except using Hierrnate 4's SessionFactory,TransacionManager etc. from org.springframework.orm.hibernate4.* package. However it started giving exception saying "Save is not valid without active transaction". After searching a bit many people seemed to have faced the problems and several people suggested not to use

        <prop key="hibernate.current_session_context_class ">thread</prop>

property and it worked. It also worked for me. All little information I could gather from the posts that it has something to do with contextual sessions and thread strategy interfering with Spring's session management strategy. But no where I could find any concrete answer. Also, why did it work with Hibernate3 and not with Hibernate4. What is the difference and what has changed? Every other configuration is same. I am not using @Transactional but the old school XML way.

    Can somebody point me to clear explaination for this behavioural difference in Hibernate3 and Hibernate4?  

回答1:

It depends on the version of spring but in general messing around with that property whilst using Spring must be avoided (unless you use JTA for transactions then you need to configure this).

As of Hibernate 3.1 there is something called contextual sessions and for that hibernate provides the CurrentSessionContext interface. There are several implementations for this (and thread is short for ThreadLocalSessionContext). Spring has its own implementation of this interface the SpringSessionContext class.

Spring by default sets the property to Springs implementation of the CurrentSessionContext, when this is set to something else (other then JTA) this will break springs ability to manage the hibernate session (and thus the transaction).

Now in older versions of spring (and I assume you also upgraded Spring to be able to use hibernate) combined with hibernate 3 there was some other trickery involved regarding getting the session (due to backwards compatibility with older 3.x versions of hibernate). This made Spring less depended on the value of that property. (Spring created a proxy for the SessionFactory and basically intercepted the getSession method to be able to manage the session).