`
曹逸飞
  • 浏览: 3354 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类
最新评论

spring + hibernate时,current_session_context_class配置问题

阅读更多

当初学使用spring来配置hibernate的事务管理时,当要把current session绑定到线程上,本人很习惯式的把hibernate的current_session_context_class的值设置为thread(hibenate native api 提供三个值:thread,jta, manage).

可是当调用session.save()方法是遇到以下的错:save is not valid without transaction.

 

applicationContext.xml

<!-- ORM的sessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <!-- Set the locations of multiple Hibernate XML config files, for example
            as classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml". -->
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />
        <property name="configurationClass" value="org.hibernate.cfg.Configuration" />
    </bean>
   
    <tx:annotation-driven/>
    <!-- 配置事务处理意见 -->
    <tx:advice id="baseAdvice" transaction-manager="txManager">
        <!-- 事务的属性 -->
        <tx:attributes>
            <tx:method name="list*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!-- 配置事务的aop -->
    <aop:config>
        <aop:pointcut id="daoPointcut" expression="execution(* com.mcao.dao.*.*(..))" />
        <aop:advisor advice-ref="baseAdvice" pointcut-ref="daoPointcut" />
    </aop:config>
   
    <!-- 定义事务管理器 -->
    <bean id="txManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <!-- 设置关联的sessionFactory -->
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
   
    <bean id="userDao" class="com.mcao.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="userService" class="com.mcao.service.UserService">
        <property name="userDao" ref="userDao" />
    </bean>

 

hibernate.cfg.xml

<session-factory>
       
        <!-- mysql jdbc 连接配置 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/test</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
       

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

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

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
       
        <!-- batch size -->
        <property name="hibernate.jdbc.batch_size">40</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>

        <mapping class="com.mcao.domain.User"/>
       
    </session-factory>

 

userDaoImpl:

public void save(Serializable domainObject) {
        Session session = sessionFactory.getCurrentSession();
        session.save(domainObject); // 错误发生在此行
    }

 

在网上查了半天,也没查到真正的原因。最后看了源代码才明白。

当current_session_context_class = thread时,具体的类就是org.hibernate.context.ThreadLocalSessionContext.

Session session = sessionFactory.getCurrentSession();只是获取当前的session,并未开启transaction(hibernate native的事务开始,是需要调用session.beginTransaction())当执行session.save(domainObject); 当前的session会被TransactionProtectionWrapper包装(代理模式),因此session.save(domainObject);被执行时,实际是通过TransactionProtectionWrapper.invoke代理执行。


这个代理添加了一些对于session调用的方法的约束,除了以下列举的方法,其他的都需要在事务中执行。由于事务未开启,所有realSession.getTransaction().isActive()为false,当然就会抛出异常了。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            try {
                // If close() is called, guarantee unbind()
                if ( "close".equals( method.getName()) ) {
                    unbind( realSession.getSessionFactory() );
                }
                else if ( "toString".equals( method.getName() )
                         || "equals".equals( method.getName() )
                         || "hashCode".equals( method.getName() )
                         || "getStatistics".equals( method.getName() )
                         || "isOpen".equals( method.getName() )
                         || "getListeners".equals( method.getName() ) //useful for HSearch in particular
                        ) {
                    // allow these to go through the the real session no matter what
                }
                else if ( !realSession.isOpen() ) {
                    // essentially, if the real session is closed allow any
                    // method call to pass through since the real session
                    // will complain by throwing an appropriate exception;
                    // NOTE that allowing close() above has the same basic effect,
                    //   but we capture that there simply to doAfterTransactionCompletion the unbind...
                }
                else if ( !realSession.getTransaction().isActive() ) {
                    // limit the methods available if no transaction is active
                    if ( "beginTransaction".equals( method.getName() )
                         || "getTransaction".equals( method.getName() )
                         || "isTransactionInProgress".equals( method.getName() )
                         || "setFlushMode".equals( method.getName() )
                         || "getSessionFactory".equals( method.getName() ) ) {
                        log.trace( "allowing method [" + method.getName() + "] in non-transacted context" );
                    }
                    else if ( "reconnect".equals( method.getName() )
                              || "disconnect".equals( method.getName() ) ) {
                        // allow these (deprecated) methods to pass through
                    }
                    else {
                        throw new HibernateException( method.getName() + " is not valid without active transaction" );
                    }
                }
                log.trace( "allowing proxied method [" + method.getName() + "] to proceed to real session" );
                return method.invoke( realSession, args );
            }
            catch ( InvocationTargetException e ) {
                if ( e.getTargetException() instanceof RuntimeException ) {
                    throw ( RuntimeException ) e.getTargetException();
                }
                else {
                    throw e;
                }
            }
        }

 

解决方法有二:

1, 添加session.beginTransaction(), 开启事务。

2, current_session_context_class对应的class设置为org.springframework.orm.hibernate3.SpringSessionContext
或者不指定(同样是org.springframework.orm.hibernate3.SpringSessionContext),在此类中,获取current session时,就已经把事务开启了。

 

 

分享到:
评论

相关推荐

    struts2.1.8 + spring2.5.6 + hibernate3.3.2整合

    &lt;property name="current_session_context_class"&gt;thread &lt;!-- 自动更新数据库表结构 --&gt; &lt;property name="hbm2ddl.auto"&gt;update &lt;!-- 使用C3P0连接池 --&gt; &lt;property name="connection.provider_class"&gt;org....

    Struts2+spring2+hibernate3实例源码-java源码

    &lt;property name="current_session_context_class"&gt;thread &lt;!-- 二级缓存配置 --&gt; &lt;property name="cache.provider_class"&gt;org.hibernate.cache.NoCacheProvider &lt;!-- 映射文件位置 --&gt; &lt;/session-factory...

    jsf+spring+hibernatre整合笔记

    - 定义当前会话上下文类(`current_session_context_class`),如`thread`,确保每个线程都有独立的会话。 - 最后,通过`&lt;mapping&gt;`标签引入实体类的映射文件,如`Classes.hbm.xml`和`Student.hbm.xml`。 3. **...

    Hibernate的配置文件

    可以设置`current_session_context_class`属性来选择Session的上下文。例如: ```xml &lt;session-factory&gt; &lt;!-- Other properties --&gt; &lt;property name="current_session_context_class"&gt;thread &lt;/session-factory...

    详细解释Spring与Hibernate的整合原理

    &lt;property name="current_session_context_class"&gt;thread &lt;/session-factory&gt; &lt;/hibernate-configuration&gt; ``` 在上述配置中,指定了 MySQL 数据库的连接信息,并配置了 C3P0 连接池参数。接下来,可以使用以下...

    spring 配置事务

    同时,为了使Hibernate的Session与Spring的事务生命周期同步,还需要在Hibernate的配置文件(如`hibernate.reveng.xml`)中启用`current_session_context_class`属性,设置为`org.springframework.orm.hibernate5....

    day36 11-Hibernate中的事务:当前线程中的session

    在Hibernate的配置中,可以通过`current_session_context_class`属性设置事务上下文。例如,将其设置为`thread`,表示使用ThreadLocal Session: ```xml &lt;property name="current_session_context_class"&gt;thread ``...

    SSH整合中 hibernate托管给Spring得到SessionFactory

    标题“SSH整合中 hibernate托管给Spring得到SessionFactory”和描述“Spring文件中的 SessionFactory中 加入为了能得到同一个Session”表明本文要讨论的是在使用Spring框架整合Hibernate时,如何实现Spring管理...

    HIBERNATE4开发文档,HIBERNATE4的变化

    同时,需要在Hibernate配置中指定`current_session_context_class`为`org.springframework.orm.hibernate4.SpringSessionContext`。 2. **缓存配置的改变** - Hibernate4中,缓存提供商由旧的类名改为`...

    javaSSH--的运行环境搭建实用.pdf

    记得在hibernate配置文件中添加`&lt;property name="current_session_context_class"&gt;thread&lt;/property&gt;`,以确保线程管理正确。 步骤三:安装Struts 通过“New -&gt; Struts -&gt; Struts 1.x Configuration”来配置Struts ...

    javaSSH--的运行环境搭建借鉴.pdf

    别忘了在`hibernate.cfg.xml`中添加`&lt;property name="current_session_context_class"&gt;thread&lt;/property&gt;`,以设置当前session上下文类。 3. **添加Struts**:选择Struts 1.2进行配置。在完成Spring配置后,删除`...

    day36 09-Hibernate中的事务:事务处理

    &lt;property name="hibernate.current_session_context_class"&gt;thread&lt;/property&gt; &lt;!-- 使用线程绑定的Session --&gt; ``` 总结来说,Hibernate的事务处理是其强大功能的重要组成部分,它提供了编程式和声明式两种方式来...

    百知教育spring笔记

    - **`&lt;prop key="hibernate.current_session_context_class"&gt;thread&lt;/prop&gt;`**:设置当前会话上下文模式为线程绑定。 - **`&lt;prop key="javax.persistence.validation.mode"&gt;none&lt;/prop&gt;`**:禁用JPA验证。 - **`...

    Java事务管理学习之Spring和Hibernate详解

    在Hibernate中,事务的上下文可以通过`hibernate.current_session_context_class`属性来设定。对于本地事务,可以设置为`thread`,对于全局事务(JTA事务),则应设置为`jta`。 当Spring与Hibernate整合时,可以...

    维生药业小项目 SSH简单学习项目

    &lt;prop key="current_session_context_class"&gt;thread &lt;prop key="hibernate.show_sql"&gt;true &lt;prop key="hibernate.format_sql"&gt;true &lt;prop key="hibernate.hbm2ddl.auto"&gt;update ...

    SSH整合(注解方式)dataSource配置defaultAutoCommit启动报错

    3. **使用合适的事务管理策略**:如果你的应用使用了Hibernate作为ORM框架,那么可能需要将`defaultAutoCommit`设置为`false`,并配置Hibernate的`current_session_context_class`为`thread`或`jta`,以配合Spring的...

    SSH第7章上机.zip ACCP8.0

    &lt;entry key="current_session_context_class" value="thread" /&gt; 加入事务管理切面类的配置 &lt;!-- 创建事务管理器(spring针对hibernate实现的事务管理的切面类) --&gt; &lt;bean id="transactionManager" class=...

    javaSSH--的运行环境搭建分享.pdf

    - 在`hibernate.cfg.xml`中,添加`&lt;property name="current_session_context_class"&gt;thread&lt;/property&gt;`,这将设置当前Session上下文为线程绑定模式。 - 删除由IDE自动生成的sessionFactory Bean,因为最终的配置...

    Spring动态多数据源配置实例Demo

    解决这个问题的方法是在Web应用中使用OpenSessionInViewFilter,同时在Hibernate配置中指定`current_session_context_class`,让Spring管理Hibernate的Session。 在提供的Demo中,这些配置和原则得到了实践。Demo...

    java常用框架学习笔记

    &lt;property name="current_session_context_class"&gt;thread &lt;!-- Disable the second-level cache --&gt; &lt;property name="cache.provider_class"&gt;org.hibernate.cache.internal.NoCacheProvider &lt;!-- Echo all ...

Global site tag (gtag.js) - Google Analytics