1、连接对象的封装
如果没有配置Filter 则生成具体的连接对象返回,否则将Connection对象包装成 ConnectionProxyImpl。
public Connection createPhysicalConnection(String url, Properties info) throws SQLException {
Connection conn;
if (getProxyFilters().isEmpty()) {
//通过驱动获取Connection
conn = getDriver().connect(url, info);
} else {
//执行责任链,并将连接对象封装成ConnectionProxyImpl
conn = new FilterChainImpl(this).connection_connect(info);
}
createCountUpdater.incrementAndGet(this);
return conn;
}
2、ConnectionProxyImpl 对象
ConnectionProxyImpl 对 Connection 的方法进行了重写,创建的 Statement 和 PreparedStatement 对象 (StatementProxyImpl、PreparedStatementProxyImpl) 都进行了扩展,基于多态的思想提高了代码的扩展性。
public Statement createStatement() throws SQLException {
//创建责任链
FilterChainImpl chain = createChain();
//执行责任链并将对象封装成 StatementProxyImpl
Statement stmt = chain.connection_createStatement(this);
//重置责任链
recycleFilterChain(chain);
return stmt;
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
//创建责任链
FilterChainImpl chain = createChain();
//执行责任链并将对象封装成 PreparedStatementProxyImpl
PreparedStatement stmt = chain.connection_prepareStatement(this, sql);
//重置责任链
recycleFilterChain(chain);
return stmt;
}
3、Statement 对象
在Druid 中将连接对象被包装成会对Statement对象进行包装, 获取到 Statement 时被包装成 DruidPooledStatement,获取PreparedStatement 对象时被装成 DruidPooledPreparedStatement。
public Statement createStatement() throws SQLException {
//先检查当前连接的状态
checkState();
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException ex) {
handleException(ex, null);
}
//设置SQL执行的超时时间
holder.getDataSource().initStatement(this, stmt);
//对Statement对象包装成DruidPooledStatement
DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt);
holder.addTrace(poolableStatement);
return poolableStatement;
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
//先检查当前连接的状态
checkState();
PreparedStatementHolder stmtHolder = null;
//通过SQL生成Statement缓存KEY
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1);
//是否开启Statement缓存
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
if (poolPreparedStatements) {
//基于LinkedHashMap实现LRUCache中获取
stmtHolder = holder.getStatementPool().get(key);
}
if (stmtHolder == null) {
try {
//获取PreparedStatement通过PreparedStatementHolder进行包装
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql));
holder.getDataSource().incrementPreparedStatementCount();
} catch (SQLException ex) {
handleException(ex, sql);
}
}
//设置超时时间和使用次数+1
initStatement(stmtHolder);
//对PreparedStatementHolder对象包装成DruidPooledPreparedStatement
DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
return rtnVal;
}
1、缓存PreparedStatement,本质上就是缓存游标,SQL语句增删改查都是游标操作,只是游标指向的目标值不同。
2、缓存的本质是使用空间换取时间,通过Druid监控后台查看PSCache的命中率 ,当命中率非常低就不推荐使用。
3、poolPreparedStatements 设置为true ,并且指定每个连接上PSCache的大小。
4、maxPoolPreparedStatementPerConnectionSize 需要进行权衡,设置过小导致命中率很低,设置过大会占用大量内存。
5、MySQL 5.5之后开始支持PSCache,MySQL PSCache是Connection 级别。
4、SQL执行
public ResultSet executeQuery() throws SQLException {
firstResultSet = true;
updateCount = null;
//SQL语句
lastExecuteSql = sql;
//SQL执行类型
lastExecuteType = StatementExecuteType.ExecuteQuery;
//执行SQL开始时间-初始化
lastExecuteStartNano = -1L;
//执行SQL的耗时-初始化
lastExecuteTimeNano = -1L;
//创建责任链并执行 SQL
return createChain().preparedStatement_executeQuery(this);
}
Druid 通过对JDBC Connection 和Statement 等对象进行了进一步的封装就可以实现对不同数据库的支持,其次通过封装可以增强和扩展更多的功能特性。
5、Filter
将不同业务逻辑块放一起,然后进行链式调用,Filter通常是FilterChain形式串在一起,可以无侵入的框架扩展。
类 | 说明 |
---|---|
Filter接口 | 定义数据库操作的方法,比如连接,提交,回滚,完整操作。 |
FilterChain接口 | 责任链接口,定义与Filter接口类似,只是说接收的参数有所区别。 |
FilterAdapter类 | 实现Filter接口,实现了大部分的方法,基本都是statement的相关实现。 |
FilterManager类 | 管理加载责任链的实现。 |
FilterEventAdapter类 | 实现Filter接口的大部分方法,提供了更规范的方式来完成对连接和 statement 前置和后置处理。 |