当初学使用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时,就已经把事务开启了。
分享到:
相关推荐
<property name="current_session_context_class">thread <!-- 自动更新数据库表结构 --> <property name="hbm2ddl.auto">update <!-- 使用C3P0连接池 --> <property name="connection.provider_class">org....
<property name="current_session_context_class">thread <!-- 二级缓存配置 --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider <!-- 映射文件位置 --> </session-factory...
- 定义当前会话上下文类(`current_session_context_class`),如`thread`,确保每个线程都有独立的会话。 - 最后,通过`<mapping>`标签引入实体类的映射文件,如`Classes.hbm.xml`和`Student.hbm.xml`。 3. **...
可以设置`current_session_context_class`属性来选择Session的上下文。例如: ```xml <session-factory> <!-- Other properties --> <property name="current_session_context_class">thread </session-factory...
<property name="current_session_context_class">thread </session-factory> </hibernate-configuration> ``` 在上述配置中,指定了 MySQL 数据库的连接信息,并配置了 C3P0 连接池参数。接下来,可以使用以下...
同时,为了使Hibernate的Session与Spring的事务生命周期同步,还需要在Hibernate的配置文件(如`hibernate.reveng.xml`)中启用`current_session_context_class`属性,设置为`org.springframework.orm.hibernate5....
在Hibernate的配置中,可以通过`current_session_context_class`属性设置事务上下文。例如,将其设置为`thread`,表示使用ThreadLocal Session: ```xml <property name="current_session_context_class">thread ``...
标题“SSH整合中 hibernate托管给Spring得到SessionFactory”和描述“Spring文件中的 SessionFactory中 加入为了能得到同一个Session”表明本文要讨论的是在使用Spring框架整合Hibernate时,如何实现Spring管理...
同时,需要在Hibernate配置中指定`current_session_context_class`为`org.springframework.orm.hibernate4.SpringSessionContext`。 2. **缓存配置的改变** - Hibernate4中,缓存提供商由旧的类名改为`...
记得在hibernate配置文件中添加`<property name="current_session_context_class">thread</property>`,以确保线程管理正确。 步骤三:安装Struts 通过“New -> Struts -> Struts 1.x Configuration”来配置Struts ...
别忘了在`hibernate.cfg.xml`中添加`<property name="current_session_context_class">thread</property>`,以设置当前session上下文类。 3. **添加Struts**:选择Struts 1.2进行配置。在完成Spring配置后,删除`...
<property name="hibernate.current_session_context_class">thread</property> <!-- 使用线程绑定的Session --> ``` 总结来说,Hibernate的事务处理是其强大功能的重要组成部分,它提供了编程式和声明式两种方式来...
- **`<prop key="hibernate.current_session_context_class">thread</prop>`**:设置当前会话上下文模式为线程绑定。 - **`<prop key="javax.persistence.validation.mode">none</prop>`**:禁用JPA验证。 - **`...
在Hibernate中,事务的上下文可以通过`hibernate.current_session_context_class`属性来设定。对于本地事务,可以设置为`thread`,对于全局事务(JTA事务),则应设置为`jta`。 当Spring与Hibernate整合时,可以...
<prop key="current_session_context_class">thread <prop key="hibernate.show_sql">true <prop key="hibernate.format_sql">true <prop key="hibernate.hbm2ddl.auto">update ...
3. **使用合适的事务管理策略**:如果你的应用使用了Hibernate作为ORM框架,那么可能需要将`defaultAutoCommit`设置为`false`,并配置Hibernate的`current_session_context_class`为`thread`或`jta`,以配合Spring的...
<entry key="current_session_context_class" value="thread" /> 加入事务管理切面类的配置 <!-- 创建事务管理器(spring针对hibernate实现的事务管理的切面类) --> <bean id="transactionManager" class=...
- 在`hibernate.cfg.xml`中,添加`<property name="current_session_context_class">thread</property>`,这将设置当前Session上下文为线程绑定模式。 - 删除由IDE自动生成的sessionFactory Bean,因为最终的配置...
解决这个问题的方法是在Web应用中使用OpenSessionInViewFilter,同时在Hibernate配置中指定`current_session_context_class`,让Spring管理Hibernate的Session。 在提供的Demo中,这些配置和原则得到了实践。Demo...
<property name="current_session_context_class">thread <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider <!-- Echo all ...