关于spring事务管理不关闭connection问题!多谢。

项目使用hibernate 2.0,spring 1.2.8,struts

问题在于连接很快就被占满,怀疑PSRING没有管理连接,仔细查看LOG发现,会有些warn提示unclosed session.在网上查了些资料,资料显示若在DAO中使用getHibernateTemplate().*时,spring会自动管理session(包括connection),而强制使用getSession()时时spring是不管理session的。而项目中大量使用这种代码,如下:
Session session = this.getSession();
// 拼装hql
String queryStr = "from DyDutyGroup dyDutyGroup where dyDutyGroup.isChange="
+ Constants.GROUP_IS_NOT_CHANGE
+ " AND PID IS NOT NULL and pid in "
+ "(select dyUser.dutyGroupId from DyUser dyUser where dyUser.userId = '"
+ userId + "'" + "and dyUser.isManager = 1" + ")";
Query query = session.createQuery(queryStr);
// 当前页通过每页数*当前页数取得要取记录的行数
query.setFirstResult(pageSize.intValue() * curPage.intValue());
// 取pageSize条
query.setMaxResults(pageSize.intValue());
java.util.List result = query.list();

其中这行Session session = this.getSession();正如资料显示,spring是不进行session管理的。资料显示需要手动关闭。

finally {
this.closeSessionIfNecessary(session);
}

这时,我做了试验,在使用getSession()方法中添加closeSessionIfNecessary(session)关闭session方法。有此方法会关闭,而有些又是报错,提示session is colsed。郁闷至极。

项目中在web.xml中配置OpenSessionInViewFilter。而applicationContext的加载方式我使用的是struts的plugin方式配置ServiceLocator,通过ServiceLocator.getInstance().getBean()方式取得bean.这里就有问题了,OpenSessionInViewFilter是setAttribute()一个context,而我并没有使用spring的Action的支持获取Context,而是通过ServiceLocator中的factory = new ClassPathXmlApplicationContext(fn);方式加载context,这时OpenSessionInViewFilter会管理session吗?也就是说OpenSessionInViewFilter会生效吗?我的lazy暂时是fasle。

我的疑惑在,如果我调用getSession(),spring是否真的不会管理session,是否需要手动关闭。若真需要手动关闭,那问题就有了,我显示的使用this.closeSessionIfNecessary(session);关才SESSION,为什么提示session is closed,是spring container在管理session吗?

具体spring事务配置如下:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${hibernate.connection.driver_class}</value>
</property>
<property name="url">
<value>${hibernate.connection.url}</value>
</property>
<property name="username">
<value>${hibernate.connection.username}</value>
</property>
<property name="password">
<value>${hibernate.connection.password}</value>
</property>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="configLocation">
<value>classpath:hibernate.duty.xml</value>
</property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>

<bean id="dyDutyConfigRuleDao"
class="com.boco.eoms.subsystem.duty.dao.impl.DyDutyConfigRuleDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>


<bean id="dyDutyConfigRuleBO"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="dyDutyConfigRuleTarget" />
</property>
<property name="transactionAttributes">
<props>
<prop key="addDyDutyDateConfigRule">
PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="updateDyDutyDateConfigRule">
PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="addDyDutyDateConfigRuleByPeriods">
PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="updateDyDutyDateConfigRuleByPeriods">
PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception
</prop>
</props>
</property>
</bean>

有时还会出现这个问题,在一个人登陆后,退出重新登陆时,就会出现如下错误。

00:42:22,302 ERROR JDBCExceptionReporter:38 - Cannot open connection

java.sql.SQLException: ORA-01017: invalid username/password; logon denied


at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)

at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)

at oracle.jdbc.ttc7.O3log.receive1st(O3log.java:407)

at oracle.jdbc.ttc7.TTC7Protocol.logon(TTC7Protocol.java:259)

at oracle.jdbc.driver.OracleConnection.<init>(OracleConnection.java:346)

at oracle.jdbc.driver.OracleDriver.getConnectionInstance(OracleDriver.java:468)

at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:314)

at java.sql.DriverManager.getConnection(DriverManager.java:512)

at java.sql.DriverManager.getConnection(DriverManager.java:140)

at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:291)

多谢。祝好~~~~~~~~~

直接调用getSession()肯定是不推荐的,可使用getHibernateTemplate().getSession,

Spring的Session是一个thread-bound Session ,就是说它是和某个线程绑定的,而这个线程往往就是承载Servlet/Jsp的那个线程,实际意思就是其生命周期scope是request/response的。所以和Servlet的context无关。

强制通过getSession()获得的Hibernate Session, 这个session可能是当前事务中之前打开的用过的那个Session,或者可能是一个新的,如果你需要必须是新的,那么通过你引用的那个HibernateTemplate中 的allowCreate为true!采取这个方案可以解决你connection关闭的错误。


谢谢banq,连接问题已解决。

现在我觉得OpenSessionInViewFilter问题很多,我使用ServiceLocator方式加载,filter也不起作用。所以想问可lazy怎么解决。十分感谢。

感谢banq

想激活lazy,目前我也只知道只能采取OpenSessionInView模式,而这个模式弊病很多,我以前帖子批判过。

这个基本问题必须由他们作者亲自来解决,可以说是一个原罪。

getHibernateTemplate().getSession()没有此方法,只有getHibernateTemplate().getSessionFactory().openSession();
一般如果用Spring来使用Hibernate时,直接使用hibernateTemplate就可以了,这时Spring会自动管理Session,但你如果getSesssion()时,此时的session是需要手动来管理的:
Session s = this.getSession();
Transaction t = s.beginTransaction();
//do something
s.save(arg0)
t.commit();
s.close();