1 Star 0 Fork 165

shk / Java-Review

forked from icanci / Java-Review 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
SSM-Mybatis3-源码解读-第6篇-数据源模块.md 59.15 KB
一键复制 编辑 原始数据 按行查看 历史
icanci 提交于 2020-09-07 10:22 . :zap:更新文件名称

SSM - Mybatis3 - 源码解读 - 第6篇 - 数据源模块

概述

  • Mybatis的数据源模块,对应 datasource包,如下

1599112847251

  • 数据源是实际开发中常用的组件之一。现在的开源的数据源都提供了比较丰富的功能。例如,连接池功能、检测连接状态等,选择性能优秀的数据源组件对于提升 ORM 框架乃至整个应用的性能都是非常重要的。
  • MyBatis自身提供了相应的数据源实现,当然 MyBatis 也提供了与第三方数据源集成的接口,这些功能都位于数据源模块之中

DataSourceFactory

  • org.apache.ibatis.datasource.DataSourceFactoryjavax.sql.DataSource 工厂接口
public interface DataSourceFactory {

    // 设置 DataSource 对象的属性
    void setProperties(Properties props);

    // 获得 DataSource对象
    DataSource getDataSource();

}
UnpooledDataSourceFactory
  • org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory ,实现 DataSourceFactory 接口,非池化的 DataSourceFactory 实现类

  • from: https://mybatis.org/mybatis-3/zh/configuration.html

  • UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:

    • driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。

    • url – 这是数据库的 JDBC URL 地址。

    • username – 登录数据库的用户名。

    • password – 登录数据库的密码。

    • defaultTransactionIsolationLevel – 默认的连接事务隔离级别。

    • defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)。查看 java.sql.Connection#setNetworkTimeout() 的 API 文档以获取更多信息。

    • 作为可选项,你也可以传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:

    • driver.encoding=UTF8

    • 这将通过 DriverManager.getConnection(url, driverProperties) 方法传递值为 UTF8encoding 属性给数据库驱动。

public class UnpooledDataSourceFactory implements DataSourceFactory {

    // 配置文件前缀
    private static final String DRIVER_PROPERTY_PREFIX = "driver.";
    private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();

    // DataSource 对象
    protected DataSource dataSource;

    // 构造方法
    public UnpooledDataSourceFactory() {
        this.dataSource = new UnpooledDataSource();
    }

    // 根据配置文件对象,赋予属性
    @Override
    public void setProperties(Properties properties) {
        // 创建一个对象
        Properties driverProperties = new Properties();
        // 创建一个 MetaObject 对象
        MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
        // 遍历 properties 对象
        for (Object key : properties.keySet()) {
            // 强转key
            String propertyName = (String) key;
            // 把以 driver. 打头的配置文件的信息初始化到driverProperties对象
            if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
                String value = properties.getProperty(propertyName);
                driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
                // 初始化到 MetaObject对象中
            } else if (metaDataSource.hasSetter(propertyName)) {
                String value = (String) properties.get(propertyName);
                Object convertedValue = convertValue(metaDataSource, propertyName, value);
                metaDataSource.setValue(propertyName, convertedValue);
            } else {
                throw new DataSourceException("Unknown DataSource property: " + propertyName);
            }
        }
        // 设置 driverProperties MetaObject中
        if (driverProperties.size() > 0) {
            metaDataSource.setValue("driverProperties", driverProperties);
        }
    }

    // 返回datasource
    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    private Object convertValue(MetaObject metaDataSource, String propertyName, String value) {
        Object convertedValue = value;
        // 获得该属性的 set 方法的参数类型
        Class<?> targetType = metaDataSource.getSetterType(propertyName);
        // 执行转化
        if (targetType == Integer.class || targetType == int.class) {
            convertedValue = Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            convertedValue = Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            convertedValue = Boolean.valueOf(value);
        }
        // 返回
        return convertedValue;
    }

}
PooledDataSourceFactory
  • org.apache.ibatis.datasource.pooled.PooledDataSourceFactory ,继承 UnpooledDataSourceFactory 类,池化的 DataSourceFactory 实现类。

  • from: https://mybatis.org/mybatis-3/zh/configuration.html

  • POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

    除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:

    • poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
    • poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
    • poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
    • poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
    • poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnectionspoolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
    • poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
    • poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
    • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {

    // 默认创建了 PooledDataSource 对象
    public PooledDataSourceFactory() {
        this.dataSource = new PooledDataSource();
    }

}
JndiDataSourceFactory
  • org.apache.ibatis.datasource.jndi.JndiDataSourceFactory ,实现 DataSourceFactory 接口,基于 JNDI 的 DataSourceFactory 实现类

  • from: https://mybatis.org/mybatis-3/zh/configuration.html

  • JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。这种数据源配置只需要两个属性:

    • initial_context – 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
    • data_source – 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

    和其他数据源配置类似,可以通过添加前缀“env.”直接把属性传递给 InitialContext。比如:

    • env.encoding=UTF8
    • 这就会在 InitialContext 实例化时往它的构造方法传递值为 UTF8encoding 属性。
public class JndiDataSourceFactory implements DataSourceFactory {

    // 配置前缀
    public static final String INITIAL_CONTEXT = "initial_context";
    public static final String DATA_SOURCE = "data_source";
    public static final String ENV_PREFIX = "env.";

    private DataSource dataSource;

    @Override
    public void setProperties(Properties properties) {
        try {
            InitialContext initCtx;
            // 获得Properties对象
            Properties env = getEnvProperties(properties);
            // 创建 InitialContext对象
            if (env == null) {
                initCtx = new InitialContext();
            } else {
                initCtx = new InitialContext(env);
            }

            // 从InitialContext上下文,获取 DataSource 对象
            if (properties.containsKey(INITIAL_CONTEXT) && properties.containsKey(DATA_SOURCE)) {
                Context ctx = (Context) initCtx.lookup(properties.getProperty(INITIAL_CONTEXT));
                dataSource = (DataSource) ctx.lookup(properties.getProperty(DATA_SOURCE));
            } else if (properties.containsKey(DATA_SOURCE)) {
                dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE));
            }

        } catch (NamingException e) {
            throw new DataSourceException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);
        }
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    private static Properties getEnvProperties(Properties allProps) {
        final String PREFIX = ENV_PREFIX;
        Properties contextProperties = null;
        for (Entry<Object, Object> entry : allProps.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if (key.startsWith(PREFIX)) {
                if (contextProperties == null) {
                    contextProperties = new Properties();
                }
                contextProperties.put(key.substring(PREFIX.length()), value);
            }
        }
        return contextProperties;
    }

}

DataSource

  • javax.sql.DataSource 是个神奇的接口,在其上可以衍生出数据连接池、分库分表、读写分离等等功能。
public interface DataSource  extends CommonDataSource, Wrapper {

    Connection getConnection() throws SQLException;

    Connection getConnection(String username, String password)
        throws SQLException;
}
UnpooledDataSource
  • org.apache.ibatis.datasource.unpooled.UnpooledDataSource ,实现 DataSource 接口,非池化的 DataSource 对象
public class UnpooledDataSource implements DataSource {

    // ClassLoader 对象
    private ClassLoader driverClassLoader;
    // Properties对象
    private Properties driverProperties;
    // 已经注册的 Driver 映射
    // KEY:Driver类名
    // VALUE:Driver对象
    private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();

    // 驱动名称
    private String driver;
    // 数据库 url
    private String url;
    // 数据库用户名
    private String username;
    // 数据库密码
    private String password;

    // 是否自动提交事务
    private Boolean autoCommit;
    // 默认的事务隔离级别
    private Integer defaultTransactionIsolationLevel;
    // 默认的网络超时时间
    private Integer defaultNetworkTimeout;

    static {
        // 初始化 drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            registeredDrivers.put(driver.getClass().getName(), driver);
        }
    }

    public UnpooledDataSource() {
    }

    // 构造函数
    public UnpooledDataSource(String driver, String url, String username, String password) {
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public UnpooledDataSource(String driver, String url, Properties driverProperties) {
        this.driver = driver;
        this.url = url;
        this.driverProperties = driverProperties;
    }

    public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
        this.driverClassLoader = driverClassLoader;
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
        this.driverClassLoader = driverClassLoader;
        this.driver = driver;
        this.url = url;
        this.driverProperties = driverProperties;
    }

    // 获取连接
    @Override
    public Connection getConnection() throws SQLException {
        return doGetConnection(username, password);
    }

    // 获取连接
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return doGetConnection(username, password);
    }

    // 设置
    @Override
    public void setLoginTimeout(int loginTimeout) {
        DriverManager.setLoginTimeout(loginTimeout);
    }

    @Override
    public int getLoginTimeout() {
        return DriverManager.getLoginTimeout();
    }

    @Override
    public void setLogWriter(PrintWriter logWriter) {
        DriverManager.setLogWriter(logWriter);
    }

    @Override
    public PrintWriter getLogWriter() {
        return DriverManager.getLogWriter();
    }

    public ClassLoader getDriverClassLoader() {
        return driverClassLoader;
    }

    public void setDriverClassLoader(ClassLoader driverClassLoader) {
        this.driverClassLoader = driverClassLoader;
    }

    public Properties getDriverProperties() {
        return driverProperties;
    }

    public void setDriverProperties(Properties driverProperties) {
        this.driverProperties = driverProperties;
    }

    public synchronized String getDriver() {
        return driver;
    }

    public synchronized void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Boolean isAutoCommit() {
        return autoCommit;
    }

    public void setAutoCommit(Boolean autoCommit) {
        this.autoCommit = autoCommit;
    }

    public Integer getDefaultTransactionIsolationLevel() {
        return defaultTransactionIsolationLevel;
    }

    public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) {
        this.defaultTransactionIsolationLevel = defaultTransactionIsolationLevel;
    }

    /**
   * Gets the default network timeout.
   *
   * @return the default network timeout
   * @since 3.5.2
   */
    public Integer getDefaultNetworkTimeout() {
        return defaultNetworkTimeout;
    }

    /**
   * Sets the default network timeout value to wait for the database operation to complete. See {@link Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}
   *
   * @param defaultNetworkTimeout
   *          The time in milliseconds to wait for the database operation to complete.
   * @since 3.5.2
   */
    public void setDefaultNetworkTimeout(Integer defaultNetworkTimeout) {
        this.defaultNetworkTimeout = defaultNetworkTimeout;
    }

    // 获取连接
    private Connection doGetConnection(String username, String password) throws SQLException {
        // 创建Properties对象
        Properties props = new Properties();
        // 设置 driverProperties 到 props中
        if (driverProperties != null) {
            props.putAll(driverProperties);
        }
        // 设置 username 和 password
        if (username != null) {
            props.setProperty("user", username);
        }
        if (password != null) {
            props.setProperty("password", password);
        }
        // 获得连接
        return doGetConnection(props);
    }

    private Connection doGetConnection(Properties properties) throws SQLException {
        // 初始化 Driver
        initializeDriver();
        // 获得 Connection 对象
        Connection connection = DriverManager.getConnection(url, properties);
        // 配置 Connection 对象
        configureConnection(connection);
        return connection;
    }

    // 初始化Driver方法
    private synchronized void initializeDriver() throws SQLException {
        // 判断 registeredDrivers 是否存在这个driver。如果不存在,进行初始化
        if (!registeredDrivers.containsKey(driver)) {
            Class<?> driverType;
            try {
                // 获得driver类
                if (driverClassLoader != null) {
                    driverType = Class.forName(driver, true, driverClassLoader);
                } else {
                    driverType = Resources.classForName(driver);
                }
                // DriverManager requires the driver to be loaded via the system ClassLoader.
                // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
                // 创建driver对象
                Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance();
                // 创建 DriverProxy 对象
                DriverManager.registerDriver(new DriverProxy(driverInstance));
                // 添加到 registeredDrivers
                registeredDrivers.put(driver, driverInstance);
            } catch (Exception e) {
                throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
            }
        }
    }

    // 配置连接的属性
    private void configureConnection(Connection conn) throws SQLException {
        // 设置,默认连接等待时间
        if (defaultNetworkTimeout != null) {
            conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), defaultNetworkTimeout);
        }
        // 设置自动提交
        if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
            conn.setAutoCommit(autoCommit);
        }
        // 设置事务的隔离级别
        if (defaultTransactionIsolationLevel != null) {
            conn.setTransactionIsolation(defaultTransactionIsolationLevel);
        }
    }

    // 内部私有静态类
    private static class DriverProxy implements Driver {
        private Driver driver;

        DriverProxy(Driver d) {
            this.driver = d;
        }

        @Override
        public boolean acceptsURL(String u) throws SQLException {
            return this.driver.acceptsURL(u);
        }

        @Override
        public Connection connect(String u, Properties p) throws SQLException {
            return this.driver.connect(u, p);
        }

        @Override
        public int getMajorVersion() {
            return this.driver.getMajorVersion();
        }

        @Override
        public int getMinorVersion() {
            return this.driver.getMinorVersion();
        }

        @Override
        public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
            return this.driver.getPropertyInfo(u, p);
        }

        @Override
        public boolean jdbcCompliant() {
            return this.driver.jdbcCompliant();
        }

        @Override
        public Logger getParentLogger() {
            return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
        }
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        throw new SQLException(getClass().getName() + " is not a wrapper.");
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public Logger getParentLogger() {
        // requires JDK version 1.6
        return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
    }

}
PooledDataSource
  • org.apache.ibatis.datasource.pooled.PooledDataSource ,实现 DataSource 接口,池化的 DataSource 实现类。
  • 实际场景,一般都不使用Mybatis的数据库连接池
public class PooledDataSource implements DataSource {

    private static final Log log = LogFactory.getLog(PooledDataSource.class);

    // PoolState 对象,记录池化的状态
    private final PoolState state = new PoolState(this);

    // UnpooledDataSource 对象
    private final UnpooledDataSource dataSource;

    // OPTIONAL CONFIGURATION FIELDS
    // 池的可以存在的连接数量
    protected int poolMaximumActiveConnections = 10;
    // 池的任意时间的空闲连接数
    protected int poolMaximumIdleConnections = 5;
    // 在被强制返回之前,池中连接(check out) 单位:毫秒
    protected int poolMaximumCheckoutTime = 20000;
    // 如果连接花费相当长的时间,连接池会打印状态日志并重新尝试获取一个连接
    protected int poolTimeToWait = 20000;
    // 这是一个关于坏连接容忍度的底层设置,作用于每一个尝试从缓存池获取连接的线程. 
    // 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接
    protected int poolMaximumLocalBadConnectionTolerance = 3;
    // 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。
    protected String poolPingQuery = "NO PING QUERY SET";
    // 是否开启侦测查询。
    protected boolean poolPingEnabled;
    // 配置 poolPingQuery 的频率,
    protected int poolPingConnectionsNotUsedFor;
	// 期望的 Connection 的类型编码
    private int expectedConnectionTypeCode;

    public PooledDataSource() {
        dataSource = new UnpooledDataSource();
    }

    public PooledDataSource(UnpooledDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public PooledDataSource(String driver, String url, String username, String password) {
        dataSource = new UnpooledDataSource(driver, url, username, password);
        expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
    }

    public PooledDataSource(String driver, String url, Properties driverProperties) {
        dataSource = new UnpooledDataSource(driver, url, driverProperties);
        expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
    }

    public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
        dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);
        expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
    }

    public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
        dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties);
        expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
    }

    // 获取数据库连接
    @Override
    public Connection getConnection() throws SQLException {
        return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
    }

    // 获取有参构造连接
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return popConnection(username, password).getProxyConnection();
    }

    // 设置连接超时时间
    @Override
    public void setLoginTimeout(int loginTimeout) {
        DriverManager.setLoginTimeout(loginTimeout);
    }

    // 获取时间
    @Override
    public int getLoginTimeout() {
        return DriverManager.getLoginTimeout();
    }

    @Override
    public void setLogWriter(PrintWriter logWriter) {
        DriverManager.setLogWriter(logWriter);
    }

    @Override
    public PrintWriter getLogWriter() {
        return DriverManager.getLogWriter();
    }

    // 设置驱动
    public void setDriver(String driver) {
        dataSource.setDriver(driver);
        forceCloseAll();
    }

    // 设置url
    public void setUrl(String url) {
        dataSource.setUrl(url);
        forceCloseAll();
    }

    public void setUsername(String username) {
        dataSource.setUsername(username);
        forceCloseAll();
    }

    public void setPassword(String password) {
        dataSource.setPassword(password);
        forceCloseAll();
    }

    public void setDefaultAutoCommit(boolean defaultAutoCommit) {
        dataSource.setAutoCommit(defaultAutoCommit);
        forceCloseAll();
    }

    public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) {
        dataSource.setDefaultTransactionIsolationLevel(defaultTransactionIsolationLevel);
        forceCloseAll();
    }

    public void setDriverProperties(Properties driverProps) {
        dataSource.setDriverProperties(driverProps);
        forceCloseAll();
    }

    /**
   * Sets the default network timeout value to wait for the database operation to complete. See {@link Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}
   *
   * @param milliseconds
   *          The time in milliseconds to wait for the database operation to complete.
   * @since 3.5.2
   */
    public void setDefaultNetworkTimeout(Integer milliseconds) {
        dataSource.setDefaultNetworkTimeout(milliseconds);
        forceCloseAll();
    }

    /**
   * The maximum number of active connections.
   *
   * @param poolMaximumActiveConnections
   *          The maximum number of active connections
   */
    public void setPoolMaximumActiveConnections(int poolMaximumActiveConnections) {
        this.poolMaximumActiveConnections = poolMaximumActiveConnections;
        forceCloseAll();
    }

    /**
   * The maximum number of idle connections.
   *
   * @param poolMaximumIdleConnections
   *          The maximum number of idle connections
   */
    public void setPoolMaximumIdleConnections(int poolMaximumIdleConnections) {
        this.poolMaximumIdleConnections = poolMaximumIdleConnections;
        forceCloseAll();
    }

    /**
   * The maximum number of tolerance for bad connection happens in one thread
   * which are applying for new {@link PooledConnection}.
   *
   * @param poolMaximumLocalBadConnectionTolerance
   *          max tolerance for bad connection happens in one thread
   *
   * @since 3.4.5
   */
    public void setPoolMaximumLocalBadConnectionTolerance(
        int poolMaximumLocalBadConnectionTolerance) {
        this.poolMaximumLocalBadConnectionTolerance = poolMaximumLocalBadConnectionTolerance;
    }

    /**
   * The maximum time a connection can be used before it *may* be
   * given away again.
   *
   * @param poolMaximumCheckoutTime
   *          The maximum time
   */
    public void setPoolMaximumCheckoutTime(int poolMaximumCheckoutTime) {
        this.poolMaximumCheckoutTime = poolMaximumCheckoutTime;
        forceCloseAll();
    }

    /**
   * The time to wait before retrying to get a connection.
   *
   * @param poolTimeToWait
   *          The time to wait
   */
    public void setPoolTimeToWait(int poolTimeToWait) {
        this.poolTimeToWait = poolTimeToWait;
        forceCloseAll();
    }

    /**
   * The query to be used to check a connection.
   *
   * @param poolPingQuery
   *          The query
   */
    public void setPoolPingQuery(String poolPingQuery) {
        this.poolPingQuery = poolPingQuery;
        forceCloseAll();
    }

    /**
   * Determines if the ping query should be used.
   *
   * @param poolPingEnabled
   *          True if we need to check a connection before using it
   */
    public void setPoolPingEnabled(boolean poolPingEnabled) {
        this.poolPingEnabled = poolPingEnabled;
        forceCloseAll();
    }

    /**
   * If a connection has not been used in this many milliseconds, ping the
   * database to make sure the connection is still good.
   *
   * @param milliseconds
   *          the number of milliseconds of inactivity that will trigger a ping
   */
    public void setPoolPingConnectionsNotUsedFor(int milliseconds) {
        this.poolPingConnectionsNotUsedFor = milliseconds;
        forceCloseAll();
    }

    public String getDriver() {
        return dataSource.getDriver();
    }

    public String getUrl() {
        return dataSource.getUrl();
    }

    public String getUsername() {
        return dataSource.getUsername();
    }

    public String getPassword() {
        return dataSource.getPassword();
    }

    public boolean isAutoCommit() {
        return dataSource.isAutoCommit();
    }

    public Integer getDefaultTransactionIsolationLevel() {
        return dataSource.getDefaultTransactionIsolationLevel();
    }

    public Properties getDriverProperties() {
        return dataSource.getDriverProperties();
    }

    /**
   * Gets the default network timeout.
   *
   * @return the default network timeout
   * @since 3.5.2
   */
    public Integer getDefaultNetworkTimeout() {
        return dataSource.getDefaultNetworkTimeout();
    }

    public int getPoolMaximumActiveConnections() {
        return poolMaximumActiveConnections;
    }

    public int getPoolMaximumIdleConnections() {
        return poolMaximumIdleConnections;
    }

    public int getPoolMaximumLocalBadConnectionTolerance() {
        return poolMaximumLocalBadConnectionTolerance;
    }

    public int getPoolMaximumCheckoutTime() {
        return poolMaximumCheckoutTime;
    }

    public int getPoolTimeToWait() {
        return poolTimeToWait;
    }

    public String getPoolPingQuery() {
        return poolPingQuery;
    }

    public boolean isPoolPingEnabled() {
        return poolPingEnabled;
    }

    public int getPoolPingConnectionsNotUsedFor() {
        return poolPingConnectionsNotUsedFor;
    }

    // 关闭所有的 activeConnections和idleConnections的连接
    public void forceCloseAll() {
        synchronized (state) {
            // 计算 expectedConnectionTypeCode
            expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
            // 遍历activeConnections关闭
            for (int i = state.activeConnections.size(); i > 0; i--) {
                try {
                    PooledConnection conn = state.activeConnections.remove(i - 1);
                    // 设置失效
                    conn.invalidate();

                    // 执行关闭
                    Connection realConn = conn.getRealConnection();
                    // 回滚事务
                    if (!realConn.getAutoCommit()) {
                        realConn.rollback();
                    }
                    // 真正关闭
                    realConn.close();
                } catch (Exception e) {
                    // ignore
                }
            }
            // 遍历 idleConnections 关闭
            for (int i = state.idleConnections.size(); i > 0; i--) {
                try {
                    // 设置失效
                    PooledConnection conn = state.idleConnections.remove(i - 1);
                    conn.invalidate();

                    // 回滚
                    Connection realConn = conn.getRealConnection();
                    if (!realConn.getAutoCommit()) {
                        realConn.rollback();
                    }
                    // 关闭真实的连接
                    realConn.close();
                } catch (Exception e) {
                    // ignore
                }
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("PooledDataSource forcefully closed/removed all connections.");
        }
    }

    public PoolState getPoolState() {
        return state;
    }

    private int assembleConnectionTypeCode(String url, String username, String password) {
        return ("" + url + username + password).hashCode();
    }

    // 将使用完的连接,添加回连接池中
    protected void pushConnection(PooledConnection conn) throws SQLException {

        synchronized (state) {
            // 从激活的连接集合中移除该连接
            state.activeConnections.remove(conn);
            // 通过ping来判断连接是否有效
            if (conn.isValid()) {
                // 判断是否超过空闲连接上限,并且和当前连接池的标识匹配
                if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
                    // 统计连接使用时长
                    state.accumulatedCheckoutTime += conn.getCheckoutTime();
                    // 回滚事务
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    // 创建 PooledConnection 对象,并且添加到空闲的连接集合中
                    PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
                    state.idleConnections.add(newConn);
                    newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
                    newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
                    // 设置原来的连接失效
                    // 为什么这里需要创建新的 PooledConnection 对象呢?
                    // 避免使用方还在使用 conn ,通过将它设置为失效,万一再次调用,会抛出异常
                    conn.invalidate();
                    if (log.isDebugEnabled()) {
                        log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
                    }
                    // 唤醒正在等待连接的线程
                    state.notifyAll();
                } else {
                    // 统计连接使用时长
                    state.accumulatedCheckoutTime += conn.getCheckoutTime();
                    // 回滚事务
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    // 真正关闭数据库连接
                    conn.getRealConnection().close();
                    if (log.isDebugEnabled()) {
                        log.debug("Closed connection " + conn.getRealHashCode() + ".");
                    }
                    // 设置原链接失效
                    conn.invalidate();
                }
            } else {
                // 失效
                if (log.isDebugEnabled()) {
                    log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
                }
                // 统计获取到的坏的连接的次数
                state.badConnectionCount++;
            }
        }
    }

    // 获取PooledConnection对象
    private PooledConnection popConnection(String username, String password) throws SQLException {
        // 标记,获取连接的时候,是否进行了等待
        boolean countedWait = false;
        // 最终获取到的连接的对象
        PooledConnection conn = null;
        // 记录当前时间
        long t = System.currentTimeMillis();
        // 记录当前方法,获取到连接的次数
        int localBadConnectionCount = 0;

        // 循环,获取可用的Connection连接
        while (conn == null) {
            synchronized (state) {
                // 空闲连接非空
                if (!state.idleConnections.isEmpty()) {
                    // Pool has available connection
                    // 通过移除的方式,获得首个空闲的连接
                    conn = state.idleConnections.remove(0);
                    if (log.isDebugEnabled()) {
                        log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
                    }
                    // 无空闲连接
                } else {
                    // Pool does not have available connection
                    // 无可用连接
                    if (state.activeConnections.size() < poolMaximumActiveConnections) {
                        // Can create new connection
                        // 创建一个连接
                        conn = new PooledConnection(dataSource.getConnection(), this);
                        // 如果是debug级别的,打印日志
                        if (log.isDebugEnabled()) {
                            log.debug("Created connection " + conn.getRealHashCode() + ".");
                        }
                    } else {
                        // Cannot create new connection
                        // 获得首个 PooledConnection对象
                        PooledConnection oldestActiveConnection = state.activeConnections.get(0);
                        long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
                        // 检测到超时
                        if (longestCheckoutTime > poolMaximumCheckoutTime) {
                            // Can claim overdue connection
                            // 对连接超时的时间统计
                            state.claimedOverdueConnectionCount++;
                            state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
                            state.accumulatedCheckoutTime += longestCheckoutTime;
                            // 从活跃的连接集合中移除
                            state.activeConnections.remove(oldestActiveConnection);
                            // 如果非自动提交的,需要进行回滚,即将原有执行中的事务,全部回滚
                            if 
                              (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                                try {
                                    oldestActiveConnection.getRealConnection().rollback();
                                } catch (SQLException e) {
                                    log.debug("Bad connection. Could not roll back");
                                }
                            }
                            // 创建新的 PooledConnection对象
                            conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
                            conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
                            conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
                            // 对old设置为无效
                            oldestActiveConnection.invalidate();
                            if (log.isDebugEnabled()) {
                                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
                            }
                        } else {
                            // 检查到未超时
                            // Must wait
                            try {
                                // 对等待连接进行统计,通过 countedWait 标识,在这个循环中,值记录一次
                                if (!countedWait) {
                                    state.hadToWaitCount++;
                                    countedWait = true;
                                }
                                if (log.isDebugEnabled()) {
                                    log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                                }
                                // 记录当前时间
                                long wt = System.currentTimeMillis();
                                // 等待,直到超时,或者 pingConnection 方法中归还连接时候唤醒
                                state.wait(poolTimeToWait);
                                // 统计等待连接的时间
                                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
                            } catch (InterruptedException e) {
                                break;
                            }
                        }
                    }
                }
                // 获取到连接
                if (conn != null) {
                    // ping to server and check the connection is valid or not
                    // 通过 ping 检测是否有效
                    if (conn.isValid()) {
                        // 如果是非自动提交的,需要进行回滚,即将原有执行中的事务,全部回滚
                        // 这里由执行了一次
                        if (!conn.getRealConnection().getAutoCommit()) {
                            conn.getRealConnection().rollback();
                        }
                        // 设置获取连接的属性
                                            conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
                        conn.setCheckoutTimestamp(System.currentTimeMillis());
                        conn.setLastUsedTimestamp(System.currentTimeMillis());
                        // 添加到活跃的连接集合
                        state.activeConnections.add(conn);
                        // 对获取成功的连接统计
                        state.requestCount++;
                        state.accumulatedRequestTime += System.currentTimeMillis() - t;
                    } else {
                        if (log.isDebugEnabled()) {
                            log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
                        }
                        // 统计获取到的坏的连接数
                        state.badConnectionCount++;
                        // 记录获取到的坏的连接的次数
                        localBadConnectionCount++;
                        // 将 conn 置空,那么可以继续获取
                        conn = null;
                        // 如果超过最大次数,抛出 SQLException异常
                        if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) {
                            if (log.isDebugEnabled()) {
                                log.debug("PooledDataSource: Could not get a good connection to the database.");
                            }
                            throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
                        }
                    }
                }
            }

        }

        // 获取不到连接,抛出SQLException异常
        if (conn == null) {
            if (log.isDebugEnabled()) {
                log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
            }
            throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
        }

        return conn;
    }

    /**
   * Method to check to see if a connection is still usable
   *
   * @param conn
   *          - the connection to check
   * @return True if the connection is still usable
   */
    
    // 通过向数据库发起 poolPingQuery 语句来发起 ping  操作,以判断数据库连接是否有效
    protected boolean pingConnection(PooledConnection conn) {
        // 用来记录ping是否成功
        boolean result = true;

        // 判断真实的连接是否已经关闭,若已经关闭,就意味着 ping肯定是失败的
        try {
            result = !conn.getRealConnection().isClosed();
        } catch (SQLException e) {
            if (log.isDebugEnabled()) {
                log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
            }
            result = false;
        }

        // 是否启用侦测查询
        if (result && poolPingEnabled && poolPingConnectionsNotUsedFor >= 0
            && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) {
            try {
                if (log.isDebugEnabled()) {
                    log.debug("Testing connection " + conn.getRealHashCode() + " ...");
                }
                Connection realConn = conn.getRealConnection();
                // 发起 ping
                try (Statement statement = realConn.createStatement()) {
                    statement.executeQuery(poolPingQuery).close();
                }
                if (!realConn.getAutoCommit()) {
                    realConn.rollback();
                }
                // 执行成功
                result = true;
                if (log.isDebugEnabled()) {
                    log.debug("Connection " + conn.getRealHashCode() + " is GOOD!");
                }
            } catch (Exception e) {
                // 标识关闭了数据库的连接
                log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage());
                try {
                    conn.getRealConnection().close();
                } catch (Exception e2) {
                    // ignore
                }
                // 标记执行失败
                result = false;
                if (log.isDebugEnabled()) {
                    log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
                }
            }
        }
        return result;
    }

    // 获取真实数据库的连接
    public static Connection unwrapConnection(Connection conn) {
        // 如果传入的是被代理连接
        if (Proxy.isProxyClass(conn.getClass())) {
            // 获取 InvocationHandler 对象
            InvocationHandler handler = Proxy.getInvocationHandler(conn);
            // 如果是 PooledConnection 就是真实的连接
            if (handler instanceof PooledConnection) {
                return ((PooledConnection) handler).getRealConnection();
            }
        }
        return conn;
    }

    @Override
    protected void finalize() throws Throwable {
        // 关闭所有的连接
        forceCloseAll();
        // 执行对象销毁
        super.finalize();
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        throw new SQLException(getClass().getName() + " is not a wrapper.");
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) {
        return false;
    }

    @Override
    public Logger getParentLogger() {
        return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
    }

}
  • popConnection 流程

PoolState

  • org.apache.ibatis.datasource.pooled.PoolState ,连接池状态,记录空闲和激活的 PooledConnection 集合,以及相关的数据统计。
public class PoolState {

    // 所属的 PooledDataSource对象
    protected PooledDataSource dataSource;

    // 空闲的 PooledConnection 集合 记录 idleConnections
    protected final List<PooledConnection> idleConnections = new ArrayList<>();
    // 空闲的 PooledConnection 集合 记录 activeConnections
    protected final List<PooledConnection> activeConnections = new ArrayList<>();
    // 全局统计 - 获取连接的次数
    protected long requestCount = 0;
    // 全局统计 - 获取连接的时间
    protected long accumulatedRequestTime = 0;
    // 全局统计 - 获取连接非超时+超时的占用时长
    protected long accumulatedCheckoutTime = 0;
    // 全局统计 - 获得连接超时的次数
    protected long claimedOverdueConnectionCount = 0;
    // 全局统计 - 获取到连接超时的占用时长
    protected long accumulatedCheckoutTimeOfOverdueConnections = 0;
    // 全局统计 - 等待连接的时间
    protected long accumulatedWaitTime = 0;
    // 全局统计 - 等待连接的次数
    protected long hadToWaitCount = 0;
    // 全局统计 - 获取到坏的连接的次数
    protected long badConnectionCount = 0;

    public PoolState(PooledDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public synchronized long getRequestCount() {
        return requestCount;
    }

    public synchronized long getAverageRequestTime() {
        return requestCount == 0 ? 0 : accumulatedRequestTime / requestCount;
    }

    public synchronized long getAverageWaitTime() {
        return hadToWaitCount == 0 ? 0 : accumulatedWaitTime / hadToWaitCount;

    }

    public synchronized long getHadToWaitCount() {
        return hadToWaitCount;
    }

    public synchronized long getBadConnectionCount() {
        return badConnectionCount;
    }

    public synchronized long getClaimedOverdueConnectionCount() {
        return claimedOverdueConnectionCount;
    }

    public synchronized long getAverageOverdueCheckoutTime() {
        return claimedOverdueConnectionCount == 0 ? 0 : accumulatedCheckoutTimeOfOverdueConnections / claimedOverdueConnectionCount;
    }

    public synchronized long getAverageCheckoutTime() {
        return requestCount == 0 ? 0 : accumulatedCheckoutTime / requestCount;
    }

    public synchronized int getIdleConnectionCount() {
        return idleConnections.size();
    }

    public synchronized int getActiveConnectionCount() {
        return activeConnections.size();
    }

    @Override
    public synchronized String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("\n===CONFINGURATION==============================================");
        builder.append("\n jdbcDriver                     ").append(dataSource.getDriver());
        builder.append("\n jdbcUrl                        ").append(dataSource.getUrl());
        builder.append("\n jdbcUsername                   ").append(dataSource.getUsername());
        builder.append("\n jdbcPassword                   ").append(dataSource.getPassword() == null ? "NULL" : "************");
        builder.append("\n poolMaxActiveConnections       ").append(dataSource.poolMaximumActiveConnections);
        builder.append("\n poolMaxIdleConnections         ").append(dataSource.poolMaximumIdleConnections);
        builder.append("\n poolMaxCheckoutTime            ").append(dataSource.poolMaximumCheckoutTime);
        builder.append("\n poolTimeToWait                 ").append(dataSource.poolTimeToWait);
        builder.append("\n poolPingEnabled                ").append(dataSource.poolPingEnabled);
        builder.append("\n poolPingQuery                  ").append(dataSource.poolPingQuery);
        builder.append("\n poolPingConnectionsNotUsedFor  ").append(dataSource.poolPingConnectionsNotUsedFor);
        builder.append("\n ---STATUS-----------------------------------------------------");
        builder.append("\n activeConnections              ").append(getActiveConnectionCount());
        builder.append("\n idleConnections                ").append(getIdleConnectionCount());
        builder.append("\n requestCount                   ").append(getRequestCount());
        builder.append("\n averageRequestTime             ").append(getAverageRequestTime());
        builder.append("\n averageCheckoutTime            ").append(getAverageCheckoutTime());
        builder.append("\n claimedOverdue                 ").append(getClaimedOverdueConnectionCount());
        builder.append("\n averageOverdueCheckoutTime     ").append(getAverageOverdueCheckoutTime());
        builder.append("\n hadToWait                      ").append(getHadToWaitCount());
        builder.append("\n averageWaitTime                ").append(getAverageWaitTime());
        builder.append("\n badConnectionCount             ").append(getBadConnectionCount());
        builder.append("\n===============================================================");
        return builder.toString();
    }

}

PooledConnection

  • org.apache.ibatis.datasource.pooled.PooledConnection ,实现 InvocationHandler 接口,池化的 Connection 对象
class PooledConnection implements InvocationHandler {

    // 关闭 Connection 方法名
    private static final String CLOSE = "close";
    // JDK Proxy 的接口
    private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };

    // 对象的标识,基于 {@link #realConnection} 求 hashCode
    private final int hashCode;
    // 所属的 PooledDataSource对象
    private final PooledDataSource dataSource;
    // 真实的Connection连接
    private final Connection realConnection;
    // 代理连接
    private final Connection proxyConnection;
    // 从连接池中,获取走的时间戳
    private long checkoutTimestamp;
    // 对象创建时间
    private long createdTimestamp;
    // 最后更新时间
    private long lastUsedTimestamp;
    // 连接的标识
    private int connectionTypeCode;
    // 是否有效
    private boolean valid;

    public PooledConnection(Connection connection, PooledDataSource dataSource) {
        this.hashCode = connection.hashCode();
        this.realConnection = connection;
        this.dataSource = dataSource;
        this.createdTimestamp = System.currentTimeMillis();
        this.lastUsedTimestamp = System.currentTimeMillis();
        this.valid = true;
        // 创建代理的对象
        this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
    }

    /**
   * Invalidates the connection.
   */
    // 设置连接无效
    public void invalidate() {
        valid = false;
    }

    /**
   * Method to see if the connection is usable.
   *
   * @return True if the connection is usable
   */
    
    // 校验连接是否可用
    public boolean isValid() {
        return valid && realConnection != null && dataSource.pingConnection(this);
    }

    /**
   * Getter for the *real* connection that this wraps.
   *
   * @return The connection
   */
    public Connection getRealConnection() {
        return realConnection;
    }

    /**
   * Getter for the proxy for the connection.
   *
   * @return The proxy
   */
    public Connection getProxyConnection() {
        return proxyConnection;
    }

    /**
   * Gets the hashcode of the real connection (or 0 if it is null).
   *
   * @return The hashcode of the real connection (or 0 if it is null)
   */
    public int getRealHashCode() {
        return realConnection == null ? 0 : realConnection.hashCode();
    }

    /**
   * Getter for the connection type (based on url + user + password).
   *
   * @return The connection type
   */
    public int getConnectionTypeCode() {
        return connectionTypeCode;
    }

    /**
   * Setter for the connection type.
   *
   * @param connectionTypeCode
   *          - the connection type
   */
    public void setConnectionTypeCode(int connectionTypeCode) {
        this.connectionTypeCode = connectionTypeCode;
    }

    /**
   * Getter for the time that the connection was created.
   *
   * @return The creation timestamp
   */
    public long getCreatedTimestamp() {
        return createdTimestamp;
    }

    /**
   * Setter for the time that the connection was created.
   *
   * @param createdTimestamp
   *          - the timestamp
   */
    public void setCreatedTimestamp(long createdTimestamp) {
        this.createdTimestamp = createdTimestamp;
    }

    /**
   * Getter for the time that the connection was last used.
   *
   * @return - the timestamp
   */
    public long getLastUsedTimestamp() {
        return lastUsedTimestamp;
    }

    /**
   * Setter for the time that the connection was last used.
   *
   * @param lastUsedTimestamp
   *          - the timestamp
   */
    public void setLastUsedTimestamp(long lastUsedTimestamp) {
        this.lastUsedTimestamp = lastUsedTimestamp;
    }

    /**
   * Getter for the time since this connection was last used.
   *
   * @return - the time since the last use
   */
    public long getTimeElapsedSinceLastUse() {
        return System.currentTimeMillis() - lastUsedTimestamp;
    }

    /**
   * Getter for the age of the connection.
   *
   * @return the age
   */
    public long getAge() {
        return System.currentTimeMillis() - createdTimestamp;
    }

    /**
   * Getter for the timestamp that this connection was checked out.
   *
   * @return the timestamp
   */
    public long getCheckoutTimestamp() {
        return checkoutTimestamp;
    }

    /**
   * Setter for the timestamp that this connection was checked out.
   *
   * @param timestamp
   *          the timestamp
   */
    public void setCheckoutTimestamp(long timestamp) {
        this.checkoutTimestamp = timestamp;
    }

    /**
   * Getter for the time that this connection has been checked out.
   *
   * @return the time
   */
    public long getCheckoutTime() {
        return System.currentTimeMillis() - checkoutTimestamp;
    }

    @Override
    public int hashCode() {
        return hashCode;
    }

    /**
   * Allows comparing this connection to another.
   *
   * @param obj
   *          - the other connection to test for equality
   * @see Object#equals(Object)
   */
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof PooledConnection) {
            return realConnection.hashCode() == ((PooledConnection) obj).realConnection.hashCode();
        } else if (obj instanceof Connection) {
            return hashCode == obj.hashCode();
        } else {
            return false;
        }
    }

    // 代理调用方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 判断是不是 close 方法,则将连接放回到连接池中,避免连接关闭
        String methodName = method.getName();
        if (CLOSE.equals(methodName)) {
            dataSource.pushConnection(this);
            return null;
        }
        try {
            // 判断非 Object 方法,则先检查连接是否可用
            if (!Object.class.equals(method.getDeclaringClass())) {
                // issue #579 toString() should never fail
                // throw an SQLException instead of a Runtime
                checkConnection();
            }
            // 反射调用对用的方法
            return method.invoke(realConnection, args);
        } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
        }

    }

    private void checkConnection() throws SQLException {
        if (!valid) {
            throw new SQLException("Error accessing PooledConnection. Connection is invalid.");
        }
    }

}
1
https://gitee.com/shokaku/Java-Review.git
git@gitee.com:shokaku/Java-Review.git
shokaku
Java-Review
Java-Review
master

搜索帮助