一 java 對(duì)數(shù)據(jù)庫的支持
java.sql 包的支持,一般使用顯示編程的方式。 connection接口、statment接口、ResultSet接口、DriverManager類。

JDBC例子
Connection con = null; //表示數(shù)據(jù)庫的連接對(duì)象
PreparedStatement pstmt = null; //表示數(shù)據(jù)庫更新操作
ResultSet result = null;
String like_name ="Tom1";
intlike_age = 12;
String sql = "select name,age,birthday from java_study.person where name like ? or age = ?";
Class.forName(DBDRIVER); //1、使用CLASS 類加載驅(qū)動(dòng)程序
System.out.println(sql);
con = DriverManager.getConnection(DBURL,DBUSER,DBPASS); //2、連接數(shù)據(jù)庫
pstmt = con.prepareStatement(sql); //使用預(yù)處理的方式創(chuàng)建對(duì)象
pstmt.setString(1, "%"+like_name+"%");
pstmt.setInt(2, like_age);
result = pstmt.executeQuery(); //執(zhí)行SQL 語句,更新數(shù)據(jù)庫
while(result.next()){
String name = result.getString("name");
intage = result.getInt("age");
Date date = result.getDate("birthday");
System.out.println(name+","+age+","+date);
}
result.close();
pstmt.close();
con.close(); // 4、關(guān)閉數(shù)據(jù)庫
JDBC事務(wù)例子
public void JdbcTransfer() {
java.sql.Connection conn = null;
try{
conn = conn =DriverManager.getConnection("jdbc:oracle:thin:@host:1521:SID","username","userpwd");
// 將自動(dòng)提交設(shè)置為 false,
//若設(shè)置為 true 則數(shù)據(jù)庫將會(huì)把每一次數(shù)據(jù)更新認(rèn)定為一個(gè)事務(wù)并自動(dòng)提交
conn.setAutoCommit(false);
stmt = conn.createStatement();
// 將 A 賬戶中的金額減少 500
stmt.execute("\
update t_account set amount = amount - 500 where account_id = 'A'");
// 將 B 賬戶中的金額增加 500
stmt.execute("\
update t_account set amount = amount + 500 where account_id = 'B'");
// 提交事務(wù)
conn.commit();
// 事務(wù)提交:轉(zhuǎn)賬的兩步操作同時(shí)成功
} catch(SQLException sqle){
try{
// 發(fā)生異常,回滾在本事務(wù)中的操做
conn.rollback();
// 事務(wù)回滾:轉(zhuǎn)賬的兩步操作完全撤銷
stmt.close();
conn.close();
}catch(Exception ignore){
}
sqle.printStackTrace();
}
}
javax.sql包的支持
Java.sql.*
包含的接口和類采用傳統(tǒng)的C/S體系結(jié)構(gòu)設(shè)計(jì)思想.主要功能針對(duì)基本數(shù)據(jù)庫編程服務(wù),如生成連接,執(zhí)行語句以及準(zhǔn)備語句和運(yùn)行批處理語句.也有一些高級(jí)功能如批處理更新,可滾動(dòng)結(jié)果集,事務(wù)隔離以及SQL數(shù)據(jù)類型.
javax.sql.*
引入了JDBC編程方面一些主要的體系結(jié)構(gòu)改變,并且為連接管理,分布式事務(wù)處理和老式連接提供了更好的抽象.這個(gè)包也引入了容器管理的連接緩沖池,分布式事務(wù)以及行集(rowset).
java.sql.是jdbc2.0之前的東西
javax.sql.包括了jdbc3.0的特性
javax.sql.提供了很多新特性,是對(duì)java.sql的補(bǔ)充,具體提供了一下方面的功能
(1)Datasource接口提供了一種可選擇性的方式去建立連接
(2)提供了連接池的支持
(3)增加了分布式的事務(wù)處理機(jī)制
(4)增加了rowset
(注意javax.sql.并不是包含java.sql.*,它倆一起組成了訪問數(shù)據(jù)的類)
在javax中我們一般要關(guān)注的點(diǎn)是:數(shù)據(jù)源對(duì)象、連接池技術(shù)、分布式事務(wù),在java只定義了接口,沒有實(shí)際的應(yīng)用,所以業(yè)內(nèi)有很多的對(duì)javax.sql的實(shí)現(xiàn)。
DataSrouce接口(數(shù)據(jù)源對(duì)象)、PooledConnection接口(池技術(shù))、XAConnection(分布式事務(wù)),這三個(gè)接口是jdbc的新特性新規(guī)范。
所以一般來說在各個(gè)廠商的實(shí)現(xiàn)來看,pooled一般指連接池,XAxxxx的只分布式。
如果要分析一個(gè)數(shù)據(jù)源的源碼的話,從這三個(gè)方面來看:

2 druid源碼分析
1 druid是由數(shù)組實(shí)現(xiàn)的
一個(gè)數(shù)據(jù)庫連接池的開源軟件。所以connection連接池的初始化、創(chuàng)建、回收、收縮、獲取,都是關(guān)鍵點(diǎn)。

通過繼承樹可以看到繼承了好的類和接口,其中主要的有兩個(gè)線,DruidAbstractDataSource和CommonDataSource。說明DruidDataSrouce是一個(gè)DataSource,可以getConnection獲取連接。

初始化時(shí)在獲取連接的時(shí)候進(jìn)行的,如果沒有手動(dòng)init的話。

二 鎖、condition、創(chuàng)建\銷毀線程
在druidDataSource中有一個(gè)重入鎖,衍生兩個(gè)condition,一個(gè)監(jiān)控連接池是否為空,一個(gè)監(jiān)控連接池不為空。
在該類中有兩個(gè)線程,一個(gè)生成連接,一個(gè)回收連接。在創(chuàng)建、獲取、回收的時(shí)候都會(huì)使用這些鎖和condition。

由于數(shù)據(jù)連接數(shù)組是公共資源,所以在多線程并行的情況下,要加鎖使用。
而在用戶線程發(fā)現(xiàn)連接池中沒有資源之后就會(huì)與創(chuàng)建連接的線程進(jìn)行通信。
druid底層是使用數(shù)組實(shí)現(xiàn)的。
獲取連接邏輯:
private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException {
if (closed) {
connectErrorCount.incrementAndGet();
throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis));
}
if (!enable) {
connectErrorCount.incrementAndGet();
throw new DataSourceDisableException();
}
final long nanos = TimeUnit.MILLISECONDS.toNanos(maxWait);
final int maxWaitThreadCount = getMaxWaitThreadCount();
DruidConnectionHolder holder;
try {
lock.lockInterruptibly(); // 獲取鎖,所有對(duì)數(shù)組可能的操作都要進(jìn)行加鎖
} catch (InterruptedException e) {
connectErrorCount.incrementAndGet();
throw new SQLException("interrupt", e);
}
try {
if (maxWaitThreadCount > 0) {
if (notEmptyWaitThreadCount >= maxWaitThreadCount) {
connectErrorCount.incrementAndGet();
throw new SQLException("maxWaitThreadCount " + maxWaitThreadCount + ", current wait Thread count "
+ lock.getQueueLength());
}
}
connectCount++;
if (maxWait > 0) {
holder = pollLast(nanos);
} else {
holder = takeLast();
}
if (holder != null) {
activeCount++;
if (activeCount > activePeak) {
activePeak = activeCount;
activePeakTime = System.currentTimeMillis();
}
}
} catch (InterruptedException e) {
connectErrorCount.incrementAndGet();
throw new SQLException(e.getMessage(), e);
} catch (SQLException e) {
connectErrorCount.incrementAndGet();
throw e;
} finally {
lock.unlock();
}
if (holder == null) {
long waitNanos = waitNanosLocal.get();
StringBuilder buf = new StringBuilder();
buf.append("wait millis ")//
.append(waitNanos / (1000 * 1000))//
.append(", active " + activeCount)//
;
List<JdbcSqlStatValue> sqlList = this.getDataSourceStat().getRuningSqlList();
for (int i = 0; i < sqlList.size(); ++i) {
if (i != 0) {
buf.append('\n');
} else {
buf.append(", ");
}
JdbcSqlStatValue sql = sqlList.get(i);
buf.append("runningSqlCount ");
buf.append(sql.getRunningCount());
buf.append(" : ");
buf.append(sql.getSql());
}
String errorMessage = buf.toString();
if (this.createError != null) {
throw new GetConnectionTimeoutException(errorMessage, createError);
} else {
throw new GetConnectionTimeoutException(errorMessage);
}
}
holder.incrementUseCount();
DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder);
return poolalbeConnection;
}
創(chuàng)建線程邏輯:
lock.lock();
try {
connections[poolingCount++] = holder;
if (poolingCount > poolingPeak) {
poolingPeak = poolingCount;
poolingPeakTime = System.currentTimeMillis();
}
errorCount = 0; // reset errorCount
notEmpty.signal();
notEmptySignalCount++;
} finally {
lock.unlock();
}
回收邏輯:
// 回收方法是在DruidPooledConnection中的close方法中調(diào)用的,DruidPooledConnection是connection的子類,所以調(diào)用方使用框架時(shí),使用close方法就是回收操作。
lock.lockInterruptibly();
try {
activeCount--;
closeCount++;
putLast(holder, lastActiveTimeMillis);
recycleCount++;
} finally {
lock.unlock();
}
收縮邏輯:
public void shrink(boolean checkTime) {
final List<DruidConnectionHolder> evictList = new ArrayList<DruidConnectionHolder>();
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}
try {
final int checkCount = poolingCount - minIdle;
final long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < checkCount; ++i) {
DruidConnectionHolder connection = connections[i];
if (checkTime) {
long idleMillis = currentTimeMillis - connection.getLastActiveTimeMillis(); // 根據(jù)timeBetweenEvictionRunsMillis進(jìn)行判斷
if (idleMillis >= minEvictableIdleTimeMillis) {
evictList.add(connection);
} else {
break;
}
} else {
evictList.add(connection);
}
}
int removeCount = evictList.size();
if (removeCount > 0) {// 挪移數(shù)組,刪除引用
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
poolingCount -= removeCount;
}
} finally {
lock.unlock();
}
for (DruidConnectionHolder item : evictList) { // 關(guān)閉真實(shí)連接
Connection connection = item.getConnection();
JdbcUtils.close(connection);
destroyCount.incrementAndGet();
}
}
3 數(shù)據(jù)源的配置
略
4 druid的代理與責(zé)任鏈

在DruidDataSource中創(chuàng)建的connection是druid自己實(shí)現(xiàn)connection接口的connectionProxyImpl類。是個(gè)代理類,代理的是connection的實(shí)現(xiàn)類,有各個(gè)開發(fā)商實(shí)現(xiàn)的具體的類。

一個(gè)使用driver生成真實(shí)的連接,一個(gè)對(duì)真實(shí)的連接進(jìn)行封裝成connectionProxy。
而在ds中會(huì)把這個(gè)代理類包裝到holder中,在使用連接池的時(shí)候,獲取holder,從holder中獲取代理連接,在proxy中獲取statment,從而執(zhí)行sql,處理返回?cái)?shù)據(jù)。

實(shí)際上,druid的對(duì)各個(gè)sql的接口都進(jìn)行了代理,進(jìn)行實(shí)現(xiàn)統(tǒng)計(jì)或者功能。通過源碼可以看到,如果配置了責(zé)任鏈的節(jié)點(diǎn)就會(huì)使用代理類,如果沒有使用則不會(huì)使用代理。

可以看出,druid的監(jiān)控統(tǒng)計(jì)是使用責(zé)任鏈模式與代理模式實(shí)現(xiàn)的。代理類的作用是調(diào)用過濾責(zé)任鏈。
