有关java.sql.SQLException: Data source is closed

线上系统出现 `java.sql.SQLException: Data source is closed` 错误。通过查阅Apache DBCP相关问题、StackOverflow讨论及源码分析,发现可能是由于Spring、Tomcat或数据源配置导致。检查发现数据源XML配置包含关闭选项,结合服务部署记录,推测在容器重启或关闭时触发异常,实际是正常行为。

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

  1. 问题的现象,线上的系统莫明的报错

### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Data source is closed
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) ~[mybatis-spring-1.1.1.jar:1.1.1]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:365) ~[mybatis-spring-1.1.1.jar:1.1.1]
    at com.sun.proxy.$Proxy71.update(Unknown Source) ~[?:?]
 ……
 ……
 
Caused by: java.sql.SQLException: Data source is closed
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1362) ~[commons-dbcp-1.4.jar:1.4]
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) ~[commons-dbcp-1.4.jar:1.4]
  1. 问题的查找,根据报错查到了以下几个链接:
    https://issues.apache.org/jira/browse/DBCP-447
    我们和提问题的人使用的dbcp版本是一致的,但最后的回答人确认不是问题。这个报错是因为1.3 1.4增加了校验的功能,如果发现数据源关闭了,则抛出这个异常。

https://stackoverflow.com/questions/33238061/receiving-data-source-is-closed-error-using-spring-boot-1-2-7-in-tomcat-8-java-8
说这个是spring4中的一个bug已经修复,但我们用的虽然是tomcat7 jdk7, 但spring用的是3的版本,所以还是不能确定是开源包的问题。

再看堆栈信息,spring调用了BasicDataSource.getConnection方法,getconnection方法又调用了createDataSource方法,遂打开dbcp源码。

    /**
     * Create (if necessary) and return a connection to the database.
     *
     * @throws SQLException if a database access error occurs
     * @return a database connection
     */
    public Connection getConnection() throws SQLException {
        return createDataSource().getConnection();//调用createDataSource()
    }

1362行的代码


    /**
     * <p>Create (if necessary) and return the internal data source we are
     * using to manage our connections.</p>
     *
     * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
     * "double checked locking" idiom in an attempt to avoid synchronizing
     * on every single call to this method.  However, this idiom fails to
     * work correctly in the face of some optimizations that are legal for
     * a JVM to perform.</p>
     *
     * @throws SQLException if the object pool cannot be created.
     */
    protected synchronized DataSource createDataSource()
        throws SQLException {
        if (closed) {
            throw new SQLException("Data source is closed");//1362行 1362行 1362行
        }

可以看到之所以抛出 Data source is closed,是因为closed=true。这个closed看起来是数据源关闭的一个标识,具体再看看它的相关代码:

    protected boolean closed;

    /**
     * <p>Closes and releases all idle connections that are currently stored in the connection pool
     * associated with this data source.</p>
     *
     * <p>Connections that are checked out to clients when this method is invoked are not affected.  
     * When client applications subsequently invoke {@link Connection#close()} to return
     * these connections to the pool, the underlying JDBC connections are closed.</p>
     * 
     * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
     * invoked result in SQLExceptions.<p>
     * 
     * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
     * and does not generate exceptions.</p>
     * 
     * @throws SQLException if an error occurs closing idle connections
     */
    public synchronized void close() throws SQLException {
        closed = true;
        GenericObjectPool oldpool = connectionPool;
        connectionPool = null;
        dataSource = null;
        try {
            if (oldpool != null) {
                oldpool.close();
            }
        } catch(SQLException e) {
            throw e;
        } catch(RuntimeException e) {
            throw e;
        } catch(Exception e) {
            throw new SQLNestedException("Cannot close connection pool", e);
        }
    }

看注释,确实是dbcp关闭数据源的方法,并且在dbcp源码中close方法没有再调用的地方了。也就是说这个closed变成true一定是外部的因素造成的。spring? tomcat?

我们的数据源xml配置中确实有close的配置:

 <bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource"  destroy-method="close">

遂继续查找资料:
https://jybzjf.iteye.com/blog/1663222
得出推论:应当是容器重启或者关闭的时候会抛出此异常

  1. 打听当天的服务部署记录,确实有上线的情况,时间点与报错时刻吻合。至此排查完毕,没理解原理,虚惊一场。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值