数据库——“该连接已关闭”问题解决方案

问题描述:对数据库的增删改查,出现“该链接已关闭”,发生概论不确定,有时成功,有时失败。

原因:Connection 是线程不安全的,当将Connection设置为全局变量,若有一个线程正将该连接close,而另一线程正在访问,则会出现“该链接已关闭”的错误。

解决方案:将Connection设置为局部变量,或每次调用时从新开一个连接。(若嫌速度慢,可以考虑使用连接池)。

修改后的代码:

package common.DaoImplement;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import common.DaoInterface.IConnectionDatabase;
import common.tool.ReaderXmlConfig;

public class ConDatabaseBySqlServerImp implements IConnectionDatabase
{
    private String driver;
    private String url;
    private String username;
    private String password;
    private Connection con = null;
    private Statement st = null;
    ResultSet rs  = null;
    /**
     * 通过读取配置文件初始化参数
     * ReaderXmlConfig,这是一个单例的类,用于得到Config.xml配置文件
     */
    public void initialize()
    {
        Document doc = ReaderXmlConfig.getInstance();
        NodeList dbs = doc.getElementsByTagName("db");
        Element db = (Element)dbs.item(0);
        String driver = db.getElementsByTagName("driver").item(0).getFirstChild().getNodeValue();
        String url = db.getElementsByTagName("url").item(0).getFirstChild().getNodeValue();
        String username = db.getElementsByTagName("username").item(0).getFirstChild().getNodeValue();
        String password = db.getElementsByTagName("password").item(0).getFirstChild().getNodeValue();
        
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;

    }
    
    /**
     * 构造方法
     * 加载数据库
     */
    public ConDatabaseBySqlServerImp(){
        initialize();
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    /**
     *对外提高Connection的接口
     *在此没有直接使用上面定义的con,而是重新定义了一个conn,即每次外部调用getConnection()方法,都将返回一个新的连接(注意在使用后关闭)
     *若此处直接是使用con,可能导致多线程并发访问,导致出错。
     */
    @Override
    public  Connection getConnection() {
        Connection conn = null;
        try {
                conn = DriverManager.getConnection(url, username, password);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        return conn;
    }
    
    /**
     * 用于内部的使用
     */
    private void getCon()
    {
        if(con == null)
        {
            try {
                con = DriverManager.getConnection(url, username, password);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 执行查询
     */
    @Override
    public ResultSet executeSql(String sql) {
        getCon();
        try {
            st = con.createStatement();
            rs = st.executeQuery(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rs;
    }

    /**
     * 执行删除,修改等无返回值的语句
     */
    @Override
    public Boolean executeUpdate(String sql) {
        getCon();
        try {
            st = con.createStatement();
            st.executeUpdate(sql);            
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 关闭连接
     */
    @Override
    public void closeConnection() {
        try{
            if(rs != null)
            {
                rs.close();
                rs = null;
            }
            if(st != null)
            {
                st.close();
                st = null;
            }
            if(con != null)
            {
                con.close();
                con = null;
            }
        }catch(SQLException e)
        {
            e.printStackTrace();
        }
    }
    
}
原文地址:https://www.cnblogs.com/ITinfo/p/3462782.html