druid连接池的问题connection holder is null

wanlitian9 发布于 2013/11/14 08:25
阅读 29K+
收藏 4

@wenshao 你好,想跟你请教个问题:

druid配置如下

driverClassName=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8
username=root
password=root

initialSize=2

maxActive=100


testOnBorrow=false
testOnReturn=false
testWhileIdle=true
validationQuery=SELECT 1 FROM DUAL
minIdle=1

maxWait=30000

经常出现

java.sql.SQLException: connection holder is null
    com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1023)
    com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:306)
    org.apache.jsp.list_jsp._jspService(list_jsp.java:121)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

连接代码如下

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSource;


import com.alibaba.druid.pool.DruidDataSourceFactory;


public class DBConnection {
    private static DruidDataSource ds;
    // 在同一个线程中保存某个对象
    private static final ThreadLocal<Connection> connLocal =
        new ThreadLocal<Connection>();
    static{
        try{//加载连接池参数,实例化连接池对象
            Properties props = new Properties();
            props.load(DBConnection.class.getClassLoader()
                .getResourceAsStream("dbcp.properties"));
            ds =(DruidDataSource) DruidDataSourceFactory
                    .createDataSource(props);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
    
    public static Connection getConnection()
            throws SQLException{
        // 获取
        Connection conn = connLocal.get();
                 System.out.println("connectCount"+ds.getConnectCount());
                 System.out.println("activeCount"+ds.getActiveCount());
                 System.out.println("PooledCount"+ds.getPoolingCount());
                 System.out.println("PooledpeakCount"+ds.getPoolingPeak());
                 
                 
                       
        
        // 获取不到创建
        if(conn==null) {
            //从连接池中获取Connection返回
            conn = ds.getConnection();
            connLocal.set(conn);
        }
        return conn;
    }
    
    //释放Connection
    public static void close() throws SQLException{
        Connection conn = connLocal.get();
        connLocal.set(null);
        
        if(conn!=null&&!conn.isClosed()){
            conn.close();
                        connLocal.remove();
        }
    }

}

druid版本是0.2.12

加载中
0
wenshao
wenshao
不要试图缓存你从连接池中拿到的连接。
0
w
wanlitian9
@wenshao 请您说的具体点好吗,非常急
0
Albert-Liu
Albert-Liu
@wenshao ,是的,我也遇到了这个问题,能说的具体点吗?
0
Albert-Liu
Albert-Liu

@wenshao

如果不在程序在缓存拿到的连接,在事务处理中如何保证获取的是同一个连接呢?

Druid提供的getConnection方法能保证在同一个线程中获取的始终是一个连接,直到显示的将连接关闭吗?

0
Albert-Liu
Albert-Liu

@wenshao

通过研究源码我可以确定"Druid提供的getConnection()或者getConnection(long maxWaitMillis)方法不能保证在同一个线程中获取的始终是一个连接,直到显示的将连接关闭吗?"。必须在程序在缓存从Druid中取出的连接才能保证现一个事务在使用的是同一个连接。 


而抛出“connection holder is null”异常的原因可能在于:

配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 
timeBetweenEvictionRunsMillis 
配置一个连接在池中最小生存的时间,单位是毫秒 
minEvictableIdleTimeMillis 
关闭长时间不使用的连接超时时间,单位秒 
removeAbandonedTimeout 

以上三个参数的值太小,以到程序还没来得及将连接归还给Druid连接池,Druid自身的DestroyConnectionThread线程已经把连接干掉,而程序在commit()连接时会执行checkState()方法,这个方法会执行以下代码: 

 if (holder == null) { 
            if (disableError != null) { 
                throw new SQLException("connection holder is null", disableError); 
            } else { 
                throw new SQLException("connection holder is null"); 
            } 
        } 

这段代码就是我们看到的“connection holder is null”异常的来源 


因为,我们需要做的就是根据Druid提供的监控信息修改这几个参数的值.

0
Albert-Liu
Albert-Liu

@wenshao

以上回答有点问题,现在修正如下:


通过研究源码我可以确定"Druid提供的getConnection()或者getConnection(long maxWaitMillis)方法不能保证在同一个线程中获取的始终是一个连接,直到显示的将连接关闭吗?"。必须在程序在缓存从Druid中取出的连接才能保证现一个事务在使用的是同一个连接。 

而抛出“connection holder is null”异常的原因可能在于: 
关闭长时间不使用的连接超时时间,单位秒
removeAbandonedTimeout


   假设这个参数的值 为30分钟,当一个连接在获取后30分钟还没释放,也就是ConnectionDruidPooledPreparedStatement对象执行完了executXXX()方法但还未执行closecommitrollback方法,对应于Connectionrunning参数的值为false,这时DuridDestroyConnectionThread线程会自动将该连接回收。当程序要commit()连接时会执行checkState()方法,这个方法会执行以下代码


1 if (holder == null) {
2            if (disableError != null) {
3                throw new SQLException("connection holder is null", disableError);
4            } else {
5                throw new SQLException("connection holder is null");
6            }
7        }


这段代码就是我们看到的“connection holder is null”异常的来源,因此,我们需要做的就是根据Druid提供的监控信息(主要看“连接持有时间分布”的值)修改这个参数的值,它的值一定要比最长的连接持有时间还要大。




顺其自然001
顺其自然001
请问这问题解决了吗?
0
科尔沁鹰隼
科尔沁鹰隼

removeAbandoned=false

removeAbandonedTimeout=1800

这两个参数应该是配合使用的 我的应用配置的是fasle 超时时间是1800秒 

还是报错提示connection holder is null

顺其自然001
顺其自然001
各位高手这问题解决了吗?
返回顶部
顶部