一 前言
近期在项目开发中,遇到了spring+hibernate开发的问题,在程序启动的过程中,出现了hibernate无法获取会话,事务无法创建的情况。追踪问题,并查文章,资料之后,发现有段程序写的有问题。另,对hibernate事务管理,springhibernate事务管理有了更深一层认识。下面说下个人见解和总结,希望有所裨益。
二 原理
getSession:
hibernate在事务管理中通过getseesion()获取会话,不能自动关闭,所以如果多线程,高并发访问的话,会话未关闭,会严重占用数据库资源。
getCurrentSession:
spring与hibernate集成后通过TransactionSynchronizationManager下的sessionholder来产生并返回session,有hibernateDaoSupport来释放资源
openSession:
有hibernateTemplate产生session,但是不会绑定到线程,需要显示关闭;若不关闭,高并发情况下回造成数据库访问缓慢
三 应用
Spring配置:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-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">
<!-- 数据源配置-->
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="autoCommitOnClose" value="true"/>
<property name="checkoutTimeout" value="${cpool.checkoutTimeout}"/>
<property name="initialPoolSize" value="${cpool.minPoolSize}"/>
<property name="minPoolSize" value="${cpool.minPoolSize}"/>
<property name="maxPoolSize" value="${cpool.maxPoolSize}"/>
<property name="maxIdleTime" value="${cpool.maxIdleTime}"/>
<property name="acquireIncrement" value="${cpool.acquireIncrement}"/>
<property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}"/>
</bean>
<!-- Hibernate常规配置-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocations">
<list>
<value>classpath*:/config/hibernate.cfg.*.xml</value>
</list>
</property>
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
</props>
</property>
</bean>
<!--Hibernate TransactionManager:hibernate事务管理-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<!-- 属性文件(jdbc,hibernate配置文件参数值)读入 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:config/jdbc.properties</value>
<value>classpath*:config/hibernate.properties</value>
</list>
</property>
</bean>
<!-- 支持 @Transactional 标记 -->
<tx:annotation-driven/>
<!-- 支持 @AspectJ 标记-->
<aop:aspectj-autoproxy/>
<!-- 以AspectJ方式 定义 AOP -->
<aop:config proxy-target-class="true">
<!-- <aop:advisor pointcut="execution(* org.my431.core..*Manager.*(..))" advice-ref="txAdvice"/> -->
<aop:advisor pointcut="execution(* org.my431.base..*Manager.*(..))" advice-ref="txAdvice"/>
</aop:config>
<!-- 基本事务定义,使用transactionManager作事务管理,默认get*方法的事务为readonly,其余方法按默认设置.
默认的设置请参考Spring文档事务一章. -->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
</beans>
注:在进行事务配置时,切面扫描范围要写正确,否则会以下错误:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
execution 中第一个*表示任何返回类型.
execution(* com.myd.spring.daoImp.*.*(..)):com.myd.spring.daoImp下子包任意任意返回类型的方法
execution(public * com.myd.spring.daoImp.*.*(..)):com.myd.spring.daoImp下子包任意任意返回类型的公有(public)方法
另外:多线程访问情况下,为了方便会使用this.getHibernateTemplate().getSessionFactory().getCurrentSession() 方法,省去手动释放事务的工作,但是仍会报以下错误,所以需要用HibernateDaoSupport的getSession()方法,并手动this.releaseSession()方法释放。
四总结
spring进行事务管理有多种配置方式,处理bean代理机制(公用代理,单个代理)稍作修改,数据源配置,事务管理器变化不大。在进行配置的时候,要根据需求决定配置方式