spring+hibernate 在oracle经常出现未提交的事务



错误描述:系统在运行一个不定的时间后,在数据库中会产生一个未提交的事务,经查访问
日志,通常是在添加或更新操作时产生的,该事务所在的连接被其他线程使用后,会导致其他数据
库操作都被阻塞,最终导致系统无法访问。该错误经开发人员手动测试和压力测试都未能重现,数
据均能正常提交,而且在多个dao中都会出现。


系统环境:
redhat5,oracle10,jdk1.6,tomcat6,spring2,hibernate3,dbcp

以下是某个Dao的典型代码及配置
public class BaseDAO {

public final int RESULT_FETCH_SIZE=100;
protected DataSource dataSource = null;
protected SessionFactory sessionFactory = null;
    protected HibernateTemplate ht = null;
    protected JdbcTemplate jt = null;

    public void setSessionFactory(SessionFactory factory)
    {
        sessionFactory = factory;
        ht  = new HibernateTemplate(sessionFactory);
    }
  
    public BaseDAO()
    {
   
    }

public DataSource getDataSource() {
return dataSource;
}

public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
jt=new JdbcTemplate(dataSource,false);
}
  
}
实现的dao
public class CmsmailboxDao extends BaseDAO implements ICmsmailboxDao{

public void createBean(final Cmsmailbox bean) throws DataAccessException{
this.ht.save(bean);
}
public Cmsmailbox getBean(String ctid) throws DataAccessException {
return (Cmsmailbox) this.ht.get(Cmsmailbox.class, ctid);
}

 public Collection getBeans(final String cmbid,final String cmbtitle,final int offset, final int rowsToReturn, final String sort,
   final String order) throws DataAccessException {
  return (Collection) ht.execute(new HibernateCallback() {
   public Object doInHibernate(Session session)
     throws HibernateException {
    StringBuffer buf = new StringBuffer();
    buf.append("from com.xxx.Cmsmailbox bean ");

    ......

    Query query = session.createQuery(buf.toString());

    ......

    return query.list();

   }

 });

}
......
}
配置文件
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>${SiteGroupDbDriver}</value>
</property>
<property name="url">
<value>${SiteGroupDbUrl}</value>
</property>
<property name="username">
<value>${SiteGroupDbUser}</value>
</property>
<property name="password">
<value>${SiteGroupDbPassword}</value>
</property>
   <property name="initialSize" value="5"/>
   <property name="maxActive" value="40" />  
       <property name="maxIdle" value="30" />  
       <property name="maxWait" value="10000" />  
       <property name="defaultAutoCommit" value="true"/>  
       <property name="removeAbandoned" value="true"/>  
       <property name="removeAbandonedTimeout" value="30"/>  
       <property name="logAbandoned" value="true"/>
       <property name="validationQuery" value="SELECT count(*) FROM SSOAPP"/>
   <property name="testOnBorrow" value="true"/>
</bean>

<bean id="baseDAO" class="com.xxx.dao.impl.BaseDAO" abstract="true">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>

<bean name="/sysadmin/distributeCmsMailbox,/sysadmin/statisticCmsMailbox"
class="com.xxx.action.CmsMailboxAction">
<property name="cmsMailboxService">
<ref bean="cmsMailboxService" />
</property>
<property name="cmsdepartmentService">
<ref bean="cmsdepartmentService" />
</property>
<property name="cmsdepartmenttypeService">
<ref bean="cmsdepartmenttypeService"/>
</property>
</bean>
<bean id="cmsMailboxService"
class="com.xxx.service.impl.CmsMailboxService">
<property name="cmsmailboxDao">
<ref bean="cmsmailboxDao" />
</property>
</bean>
<bean id="cmsmailboxDao" class="com.xxx.dao.impl.CmsmailboxDao"
parent="baseDAO">
</bean>

以上是dao的一种典型配置

下面是事务管理器的配置,实际上我的应用并未用到事务处理,只是出现上述错误后,怀疑
是未加事务管理器的问题,结果加上后问题依旧

        <bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                <property name="sessionFactory"><ref
bean="sessionFactory"/></property>
        </bean>
        <bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
                <property name="transactionManager" ref="transactionManager"/>
                <property name="transactionAttributes">
                        <props>
                                <prop key="*">PROPAGATION_REQUIRED</prop>
                        </props>
                </property>
        </bean>
        <bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
                <property name="beanNames">
                  <value>*Dao</value>
                </property>
                <property name="interceptorNames">
                        <list>
                                <value>transactionInterceptor</value>
                        </list>
                </property>
        </bean>

目前已经可以排除的可能:1、数据库,在sqlserver下也会出现;2、jdbc驱动;3、hibernate及spring的版本;4、连接池,dbcp和c3p0都会出现

感觉对于spring中使用hibernate的方式应该没有错误,应该是哪个地方的配置或是某个部分对整体架构产生了影响,希望大家都能来讨论下,给点思路

 


问题补充
现在已经是true了
那个不设是所有的操作都不会写到数据库
问题补充
昨天用wvs测安全,居然把这个错误重现了,初步判断是和HibernateTemplate的并发有关

3个回答

我觉得这里根本的问题在于你的事务管理方式有问题,你有些事务没有被真真管理起来,这就造成了hibernate打开的session没有收回,最终把dbcp的连接池耗完了(你设的是40个),你可以看看当出现问题时,你的dbcp的连接数是不是到最大了,你也可以看看你的事务是不是真的起作用了!

不好意思没看清楚

你的BaseDAO注入HibernateTemplate 的方式就怪怪的,

你应该用推荐的通用方式注入

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" >  
    <property name="sessionFactory" ref="sessionFactory" />  
</bean>  
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问