常见的数据源组件都实现了java.sql.DataSource接口。MyBatis也是这个套路。
从上图可以看出:MyBatis使用不同的DataSourceFactory接口实现创建不同类型的DataSource。工厂模式
DataSourceFactory
public interface DataSourceFactory {
//设置DataSoutce相关属性,一般跟在初始化完成之后
void setProperties(Properties props);
//获取DataSoutce对象
DataSource getDataSource();
}
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();
protected DataSource dataSource;
//构函初始化dataSource
public UnpooledDataSourceFactory() {
this.dataSource = new UnpooledDataSource();
}
@Override
public void setProperties(Properties properties) {
Properties driverProperties = new Properties();
//创建DataSource相应的MetaObject
MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
//遍历
for (Object key : properties.keySet()) {
String propertyName = (String) key;
if (propertyName.startsWith("driver.")) {
//以"driver."开始的配置是对DataSource的配置保存到driverProperties
String value = properties.getProperty(propertyName);
driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
} else if (metaDataSource.hasSetter(propertyName)) {//是否有该属性的setter方法
String value = (String) properties.get(propertyName);
Object convertedValue = convertValue(metaDataSource, propertyName, value);
metaDataSource.setValue(propertyName, convertedValue);
} else {
throw new DataSourceException("Unknown DataSource property: " + propertyName);
}
}
if (driverProperties.size() > 0) {
//设置datasource.driverProperties相关属性值
metaDataSource.setValue("driverProperties", driverProperties);
}
}
@Override
public DataSource getDataSource() {
return dataSource;
}
private Object convertValue(MetaObject metaDataSource, String propertyName, String value) {
Object convertedValue = value;
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;
}
}
复制代码
UnpooledDataSource
public class UnpooledDataSource implements DataSource {
private ClassLoader driverClassLoader;//加载Driver类的加载器
private Properties driverProperties;//数据库连接驱动的相关配置
//缓存所有已注册的数据库连接驱动
private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();
private String driver;//驱动名称
private String url;
private String username;
private String password;
private Boolean autoCommit;
private Integer defaultTransactionIsolationLevel;//事务隔离级别
static {
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) throws SQLException {
DriverManager.setLoginTimeout(loginTimeout);
}
@Override
public int getLoginTimeout() throws SQLException {
return DriverManager.getLoginTimeout();
}
@Override
public void setLogWriter(PrintWriter logWriter) throws SQLException {
DriverManager.setLogWriter(logWriter);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
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;
}
private Connection doGetConnection(String username, String password) throws SQLException {
Properties props = new Properties();
if (driverProperties != null) {
props.putAll(driverProperties);
}
if (username != null) {
props.setProperty("user", username);
}
if (password != null) {
props.setProperty("password", password);
}
return doGetConnection(props);
}
private Connection doGetConnection(Properties properties) throws SQLException {
initializeDriver(); //1.初始化驱动
//2.从DriverManager中获取连接,获取新的Connection对象
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);//3.配置autoCommit和隔离级别
return connection;
}
private synchronized void initializeDriver() throws SQLException {
if (!registeredDrivers.containsKey(driver)) {//检测驱动是否注册
Class<?> driverType;
try {
if (driverClassLoader != null) {//注册驱动
driverType = Class.forName(driver, true, driverClassLoader);
} else {
driverType = Resources.classForName(driver);
}
//创建Driver对象
Driver driverInstance = (Driver)driverType.newInstance();
//注册驱动
DriverManager.registerDriver(new DriverProxy(driverInstance));
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 (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 only valid jdk7+
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 only valid jdk7+
public Logger getParentLogger() {
// requires JDK version 1.6
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
}
}
复制代码
PooledDataSource
依赖的组件
PooledDataSource并不会直接管理connection对象,而是管理PooledConnection对象。PooledConnection中封装真正的连接对象以及其代理对象(通过jdk代理)
# PooledDataSource
//通过PoolState管理池状态并记录统计信息
private final PoolState state = new PoolState(this);
//生成真正的连接对象,构造函数中初始化该字段
private final UnpooledDataSource dataSource;
protected int poolMaximumActiveConnections = 10;//最大活跃连接
protected int poolMaximumIdleConnections = 5;//最大空闲连接
protected int poolMaximumCheckoutTime = 20000;//最大checkout时长
protected int poolTimeToWait = 20000;//无法获取链接时,线程要等待的时间
protected int poolMaximumLocalBadConnectionTolerance = 3;
//检测连接是否可用,会发送一个测试SQL语句
protected String poolPingQuery = "NO PING QUERY SET";
protected boolean poolPingEnabled;//是否允许发送测试SQL语句
//当连接超过poolPingConnectionsNotUsedFor毫秒未用时,发送一次测试SQL,检测连接是否正常
protected int poolPingConnectionsNotUsedFor;
private int expectedConnectionTypeCode;
//获取链接过程
public Connection getConnection() throws SQLException {
return popConnection(dataSource.getUsername(), dataSource.getPassword())
.getProxyConnection();//得到连接后,返回代理。(这个是在初始化PooledConnection时,生成的代理)
}
// 返回可用的PooledConnection
private PooledConnection popConnection(String username, String password) throws SQLException {
boolean countedWait = false;
PooledConnection conn = null;
long t = System.currentTimeMillis();
int localBadConnectionCount = 0;
while (conn == null) {
synchronized (state) {
if (!state.idleConnections.isEmpty()) {
// 连接池中有空闲连接,取出第一个
conn = state.idleConnections.remove(0);
} else {
// // 连接池中没有空闲连接,则取当前正在使用的连接数小于最大限定值
if (state.activeConnections.size() < poolMaximumActiveConnections) {
// // 创建一个新的connection对象
conn = new PooledConnection(dataSource.getConnection(), this);
if (log.isDebugEnabled()) {
log.debug("Created connection " + conn.getRealHashCode() + ".");
}
} else {
// 当活动连接池已满,不能创建时,取出活动连接池的第一个,即最先进入连接池的PooledConnection对象
// 计算它的校验时间,如果校验时间大于连接池规定的最大校验时间,则认为它已经过期了,
// 利用这个PoolConnection内部的realConnection重新生成一个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");
}
}//如果过期,创建新的连接放入活跃池。//这里创建代理
conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
oldestActiveConnection.invalidate();
if (log.isDebugEnabled()) {
log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
}
} else {
//如果不能释放,则必须等待有
try {
if (!countedWait) {
state.hadToWaitCount++;
countedWait = true;
}
long wt = System.currentTimeMillis();
state.wait(poolTimeToWait);
state.accumulatedWaitTime += System.currentTimeMillis() - wt;
} catch (InterruptedException e) {
break;
}
}
}
} //如果获取PooledConnection成功,则更新其信息
if (conn != null) {
// ping to server and check the connection is valid or not
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 {
state.badConnectionCount++;
localBadConnectionCount++;
conn = null;
if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) {
throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
}
}
}
}
}
####返回连接
//通过PooledConnection.invoke()方法我们知道,调用连接的代理的close方法时,调用的是//PooledDataSource.pushConnectioin方法,将PooledConnction归还给连接池,供之后重用。
protected void pushConnection(PooledConnection conn) throws SQLException {
synchronized (state) {//同步
state.activeConnections.remove(conn);//从活跃集合中移除该PooledConnection对象
if (conn.isValid()) {//检测PooledConnection是否有效
if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {//空闲连接是否达到上限,以及连接是否为该连接池连接
state.accumulatedCheckoutTime += conn.getCheckoutTime();//累积checkout时长
if (!conn.getRealConnection().getAutoCommit()) {//回滚未提交的事务
conn.getRealConnection().rollback();
}//为返还的连接创建新的PooledConnection对象
PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
state.idleConnections.add(newConn);//添加到idle集合
newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
conn.invalidate();//将原pooledConnecion设为无效
state.notifyAll();//唤醒阻塞等待的线程
} else {//空闲连接到达上限或pooledConnection对象不属于该池
state.accumulatedCheckoutTime += conn.getCheckoutTime();//累积checkout时长
if (!conn.getRealConnection().getAutoCommit()) {
conn.getRealConnection().rollback();
}
conn.getRealConnection().close();//关闭真正的连接
conn.invalidate();//将PooledConncetion设为无效
}
} else {
state.badConnectionCount++;//统计无效PooledConnection对象个数
}
}
}
//检测有效性的方法
public boolean isValid() {
return valid && realConnection != null
&& dataSource.pingConnection(this);//检测真正连接是否有用
}
//执行测试SQL
protected boolean pingConnection(PooledConnection conn) {
boolean result = true;//记录ping操作是否成功
try {
result = !conn.getRealConnection().isClosed();//检测真正的连接是否关闭
} catch (SQLException e) {
result = false;
}
if (result) {
if (poolPingEnabled) {//是否执行SQL语句
if (poolPingConnectionsNotUsedFor >= 0 && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) {//长时间未使用的连接,才需要ping来检测是否正常
try {//执行测试语句
Connection realConn = conn.getRealConnection();
try (Statement statement = realConn.createStatement()) {
statement.executeQuery(poolPingQuery).close();
}
if (!realConn.getAutoCommit()) {
realConn.rollback();
}
result = true;
} catch (Exception e) {
try {
conn.getRealConnection().close();
} catch (Exception e2) {
//ignore
}
result = false;
}
}
}
}
return result;
}
复制代码
PooledConnection核心字段:
//当前PooledConnection所属的PooledDataSource。
private final PooledDataSource dataSource;
private final Connection realConnection;//真正的数据连接
private final Connection proxyConnection;//连接的代理
private long checkoutTimestamp;//从池中取出该连接的时间
private long createdTimestamp;//该连接的创建时间
private long lastUsedTimestamp;//最后一次使用时间
private int connectionTypeCode;//url 用户名密码得到的hash,标示连接所在的连接池
private boolean valid;//检测当前连接是否有效。主要是防止程序通过close()方法将连接归还池后,依然通过该连接操作数据库
//当调用关闭的时候,回收此Connection到PooledDataSource中
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
//若调用close(),则将其重新放入池中,而不是真正关闭连接
if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
dataSource.pushConnection(this);
return null;
} else {
try {
if (!Object.class.equals(method.getDeclaringClass())) {
//通过valid字段检测连接是否有效
checkConnection();
}//调用真正数据库对象的对应方法
return method.invoke(realConnection, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
//池和连接的理解https://www.cnblogs.com/panxuejun/p/6403760.html
//http://shift-alt-ctrl.iteye.com/blog/1967020
//数据库连接池在初始化时,会创建一定数量的连接放在池中备用。
//当池中连接全部用完,请求就会进入阻塞队列等待。
复制代码
PoolState是用于管理PooledConnection对象状态的组件,通过两个ArrayList<>管理空闲和活跃两种状态。
protected final List<PooledConnection> idleConnections = new ArrayList<>();//空闲
protected final List<PooledConnection> activeConnections = new ArrayList<>();//活跃
//统计的字段
protected long requestCount = 0;//请求连接次数
protected long accumulatedRequestTime = 0;//获取连接的累积时间
protected long accumulatedCheckoutTime = 0;//所有连接累积CheckoutTime时长
protected long claimedOverdueConnectionCount = 0;//超时连接个数
protected long accumulatedCheckoutTimeOfOverdueConnections = 0;//累积超时时间
protected long accumulatedWaitTime = 0;//累积等待时间
protected long hadToWaitCount = 0;//等待次数
protected long badConnectionCount = 0;//无效的连接数
复制代码