Spring不对Hibernate原方法操作数据库提供连接关闭服务

在Spring框架中使用Hibernate时遇到数据库连接未关闭导致应用异常的问题。通过排查,发现不是死循环、死锁或内存溢出,而是数据库连接在多次操作后未及时关闭,处于sleeping状态。Spring虽然配置了数据源关闭,但直接使用Hibernate的session方法不会触发Spring的关闭机制。解决方法是利用Spring的HibernateDaoSupport提供的getHibernateTemplate进行数据库操作,确保连接的正确关闭。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前几天我把我之前运用Hibernate+struts1.x框架开发的web项目搬到Spring框架上,其中Hibernate和struts都配置到applicationContext.xml文件上,通过初步测试发现所有线都已经打通了。到今天,我同样是运行该项目,发现一个很诡异的问题就是,当我连续地点击访问数据库的时候,前几次还是没有问题的,但点击多几次就发现项目就死了,所有需要连接数据库的操作的不行了,点其他不用连接数据库的操作还是可以的。同时项目后台并没有报什么错误。一下子就懵逼了,无从下手,因为这个并不是编译或者运行错误。
静下心来细想一下,出现这种现象第一种:中可能性就是出现死循环,但我检查java中并没有死循环(因为就算我点击同一个按钮,调用同一个方法,点击几次之后也会出现这种情况);第二种:就是有线程异步造成死锁的原因,但是就算我加上同步锁还是这样的情况,所以也不是死锁的问题;第三种:就是内存溢出,但如果内存溢出时会报错的,并且就点击几次去连接数据库也不会出现内存溢出。还会是什么问题呢?还有就是这个项目很奇葩的问题就是访问数据库就会出现这种问题,而访问其他的就正常,所以也许是数据库的问题。这时才突然想起如果数据库连接不及时关闭也会出现这种问题,但查看一下Spring的配置,数据源已经配置了关闭。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
 <property name="driverClassName" value="${jdbc.driver}"></property>
 <property name="url" value="${jdbc.url}"></property>
 <property name="username" value="${jdbc.username}"></property>
 <property name="password" value="${jdbc.password}"></property>
 </bean>

还会是什么问题呢?并且一开始就可以访问数据库,说明也不是数据库驱动的问题。想一下还是想去看一下数据库那边有没有及时关闭连接了没(也是一种走投无路的尝试了),我用的是sql server 2014数据库所以用下面的语句查询:

SELECT * FROM  [Master].[dbo].[SYSPROCESSES] WHERE [DBID] IN 
(
  SELECT  [DBID] FROM  [Master].[dbo].[SYSDATABASES]  WHERE  NAME='数据库名'
)    

出现的结果出我意料,竟然所有的数据库连接都sleeping状态
这里写图片描述

这个说明数据库连接并没有及时关闭,所有都是sleeping状态,学过java多线程核心同学的都知道,sleeping没有释放锁,所以其他线程只能等待锁,这个也就是为什么我们点击去访问数据库的操作一直没有反应,同时没有报错,因为后面点击的在等待锁。
我们再回来问题的原点,我们在spring中明明配置了,数据源关闭,但为什么事实上并没有关闭。spring框架中明明写着:在Spring里,Hibernate的资源要交给Spring来管理,Hibernate及其SessionFactory等只是Spring一个特殊的bean,由Spring负责实例化与销毁。因此,Dao曾只需要继承HibernateDaoSupport,而不需要与Hibernate的Api打交道,不需要开启,关闭Hibernate的session、Transaction,Spring自动维护这些对象。
我查询了相关的资料,都说Spring会自动关闭数据库的连接,我反复检查我的代码,再与别人的源码比较,发现我用的是Hibernate框架提供的方法,即session=this.getSession(true)获取Session。而不是Spring框架提供的getHibernateTemplate()来操作数据库。难道是这里出现问题吗?我决定写一个测试类看一下:

接口类:(Spring需要接口编程)
package com.cph.daoInter;

import java.util.List;

import com.cph.domain.Cat;

public interface CatInter {
public List listCat();
}
实现类:
package com.cph.daoImpl;

import java.util.List;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.cph.daoInter.CatInter;
import com.cph.domain.Cat;

public class CatImpl extends HibernateDaoSupport implements CatInter {
    @Override
    public List listCat() {
        // TODO Auto-generated method stub
        String hql="from Cat";
//      return getHibernateTemplate().find(hql);
        return this.getSession(true).createQuery(hql).list();
    }

}
applicationContext.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<beans 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/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.springframework.org/schema/beans">
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
 <property name="driverClassName" value="com.microsoft.jdbc.sqlserver.SQLServerDriver"></property>
 <property name="url" value="jdbc:sqlserver://localhost:1433;DatabaseName=cph"></property>
 <property name="username" value="sa"></property>
 <property name="password" value="chenpeihong"></property>
 </bean>
 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" destroy-method="destroy">
 <property name="dataSource" ref="dataSource"></property>
 <property name="mappingResources">
 <list>
 <value>/com/cph/domain/cat.hbm.xml</value>
 </list>
 </property>
 <property name="hibernateProperties">
 <props>
  <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
  <prop key="hibernate.show_sql">true</prop>
  <prop key="hibernate.hbm2ddl.auto">update</prop>
 </props>
 </property>
 </bean>
  <bean id="catImpl" class="com.cph.daoImpl.CatImpl">
 <property name="sessionFactory" ref="sessionFactory"></property>
 </bean>
</beans> 
测试类:
package com.cph.texts;

import java.util.List;

import org.hibernate.hql.ast.tree.FromClause;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

import com.cph.daoInter.CatInter;
import com.cph.domain.Cat;
import com.cph.servicesInter.hibernateServiceInter;

public class HibernateText {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
   XmlBeanFactory xmlBeanFactory=new XmlBeanFactory(new ClassPathResource("hibernateApplicationContexnt.xml"));

   CatInter catInter=(CatInter) xmlBeanFactory.getBean("catImpl");
   for(int i=0;i>=0;i++){
       catInter.listCat();
   }

    }

}

发现用这样写,后台发出八条的sql语句后就再也没有打印了,同时任务按钮一直是红色的,说明线程没有结束:
这里写图片描述
在数据库那边显示的连接线程全都是sleeping状态:
这里写图片描述
而如果把实现类的修改如下:

package com.cph.daoImpl;

import java.util.List;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.cph.daoInter.CatInter;
import com.cph.domain.Cat;

public class CatImpl extends HibernateDaoSupport implements CatInter {
    @Override
    public List listCat() {
        // TODO Auto-generated method stub
        String hql="from Cat";
        return getHibernateTemplate().find(hql);
//      return this.getSession(true).createQuery(hql).list();
    }

}

后台一直在打印sql语句,同时sql server数据库在sleeping 和runnable之间跳转,说明数据库得到正常的关闭。
所以我发现了问题的所在了,是因为Spring框架对Hibernate框架提供的方法,即session=this.getSession(true)获取Session来操作数据库不提供连接关闭服务,要用Spring提供的通过继承HibernateDaoSupport提供的getHibernateTemplate来操作数据库,后面这样修改了源码,发现正确。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值