1. 程式人生 > >Druid資料連線池原始碼分析

Druid資料連線池原始碼分析

Druid是阿里巴巴公司的資料庫連線池工具,昨天突然想學習一下阿里的druid原始碼,於是下載下來分析了一下。也就2個多小時粗略看了一下,中間有些知識點沒見過,不懂,現查BAIDU學習。簡單總結一下,邊總結邊繼續看程式碼,估計錯誤不少,歡迎指正! 

    在自己看之前,想找找druid原始碼分析,居然在BAIDU上搜索不到任何資訊,只是介紹如何配置,只能自己看過來了。這裡的介紹,細節不說了,著眼於大方向與設計思路。 

1。為監控而生,那麼何時,又如何監控呢? 
    簡單的操作資料庫通常涉及datasource,connection,preparedstatement ,ResultSet等東西,如果我要監控這些,必然要建些代理類。 
   我們的操作都由代理類完成,在完成的過程中,產生監控的資料。 
   druid號稱為監控而生,監控功能就是一根針,正所謂見縫插針,沒有縫隙就要創造縫隙,所以就要建個代理類,代理類與被代理理之間就是縫隙。而代理物件必然持有被代理物件。 
    public interface PreparedStatementProxy extends PreparedStatement, StatementProxy 
    作為實現類:PreparedStatementProxyImpl,就持有一個java.sql.PreparedStatement。 
    隨便看看它的查詢方法: 
    public ResultSet executeQuery() throws SQLException { 
..... 
        return createChain().preparedStatement_executeQuery(this);//產生過濾鏈,並由過濾鏈執行。 
    } 
  FilterChainImpl中有: 
Java程式碼  收藏程式碼
  1. public ResultSetProxy preparedStatement_executeQuery(PreparedStatementProxy statement) throws SQLException {  
  2.     if (this.pos < filterSize) {  
  3.         return nextFilter().preparedStatement_executeQuery(this, statement);  
  4.     }  
  5.     ResultSet resultSet = statement.getRawObject().executeQuery();  
  6.     return wrap(statement, resultSet);  
  7. }  

    上面的方法說明:在執行查詢前,要經過過濾鏈處理,等處理完了,再由statement執行,執行完了,得到一個ResultSet後,包裝一個產生最後返回的代理類。 

2.說說統計過濾器吧,只是過濾鏈上的一環 
   此模式見的最多的就是web.xml中配置的過濾器filter了,你配置幾個過濾器filter,都實現了dofilter()方法,那麼把filter們組織成來,放在filterchain的List之類的容器中,那麼就可以迴圈執行dofilter來處理些東東。可以看出filterchain持有所有的filter,那filter執行後,要告訴filterchain執行下一個,所以fiter還必須持有filterchain。但filter不需要一直持有filterchain物件,只是臨時持有一會,所以filterchain是作為方法的引數傳進來的。這也說明filter可以是這個chain中的一環,也可以同時是另一個chain中的一環,誰來都行。 
這個過程,又點象觀察者模式,又象回撥模式。 
   看個簡單的,StatFilter中的一個統計連線提交的方法:(StatFilter中的過濾方法超級多,對各種資料庫操作都記賬;當然logfilter中也一樣,防禦SQL注入攻擊的WallFilter,估計也一樣:) 
Java程式碼  收藏程式碼
  1. @Override  
  2. public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException {  
  3.     chain.connection_commit(connection);  
  4.     JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();  
  5.     dataSourceStat.getConnectionStat().incrementConnectionCommitCount();  
  6. }  

  先是讓chain去作一步(就是nextFilter開始幹活,所有的filter都幹完了,就真正commit一下)然後,對資料來源的commit的操作計數進行增加。 
Java程式碼  收藏程式碼
  1. public void connection_commit(ConnectionProxy connection) throws SQLException {  
  2.     if (this.pos < filterSize) {  
  3.         nextFilter().connection_commit(this, connection);//讓下一個幹活  
  4.         return;  
  5.     }  
  6.     connection.getRawObject().commit();//都幹完了,才真正提交。這個連線也是一個代理,讓裡面真正的java.sql.connection提交。  
  7. }  
  8. private Filter nextFilter() {  
  9.     Filter filter = getFilters().get(pos++);  
  10.     return filter;  
  11. }  

DataSourceProxyConfig中有一個private final List<Filter> filters = new ArrayList<Filter>();//就是普通的arraylist放過濾器。 

上面兩點合在一起,就是原來執行一個數據庫操作,現在給代理類執行,執行中先經過一個個過濾器進行統計,之後再真正執行資料庫操作。對終端使用者透明的。 

3.統計的東東怎麼記錄的呢? 
在stat包裡面,隨便找一個物件看看吧。比如:JdbcStatementStat 
.......................... 
Java程式碼  收藏程式碼
  1. private final AtomicLong    createCount      = new AtomicLong(0);                                     // 執行createStatement的計數  
  2. private final AtomicLong    prepareCount     = new AtomicLong(0);                                     // 執行parepareStatement的計數  
  3. private final AtomicLong    prepareCallCount = new AtomicLong(0);                                     // 執行preCall的計數  
  4. private final AtomicLong    closeCount       = new AtomicLong(0);   

..................................... 
哇哦,一大堆統計計數器,都是AtomicLong的,就是執行緒同步的,增加計數時呼叫它的incrementAndGet()方法。不過TableStat中就是普通的int了,呵呵。 

4.說說最上面的藍字的執行 
ResultSet resultSet = statement.getRawObject().executeQuery(); 
     PreparedStatementProxy代理了一個實現了java.sql.statement介面的物件,所以它用那個物件執行查詢。那個物件是什麼樣的呢? 
     對了,是這個:DruidPooledPreparedStatement,看的出,這個傢伙也是代理了別人,因為它用stat來做查詢,只是代理前後做了點其它事情。 
Java程式碼  收藏程式碼
  1. public ResultSet executeQuery() throws SQLException {  
  2.     checkOpen();  
  3.     incrementExecuteCount();  
  4.     transactionRecord(sql);  
  5.     oracleSetRowPrefetch();  
  6.     conn.beforeExecute();  
  7.     try {  
  8.         ResultSet rs = stmt.executeQuery();  
  9.         if (rs == null) {  
  10.             return null;  
  11.         }  
  12.         DruidPooledResultSet poolableResultSet = new DruidPooledResultSet(this, rs);  
  13.         addResultSetTrace(poolableResultSet);  
  14.         return poolableResultSet;  
  15.     } catch (Throwable t) {  
  16.         throw checkException(t);  
  17.     } finally {  
  18.         conn.afterExecute();  
  19.     }  
  20. }  

    其中:addResultSetTrace是把查詢結果放在List<ResultSet>       resultSetTrace;中。為何? 

5.看看幾個Holder是幹什麼的? 
DruidConnectionHolder中有什麼?new DruidPooledConnection時,正好用這個holder。 
Java程式碼  收藏程式碼
  1.     private final DruidAbstractDataSource       dataSource;  
  2.     private final Connection                    conn;  
  3.     private final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();  
  4.     private final List<StatementEventListener>  statementEventListeners  = new CopyOnWriteArrayList<StatementEventListener>();  
  5.     private PreparedStatementPool               statementPool;   //這是一個LRU演算法的池。放的就是下面的PreparedStatementHolder!!!!  
  6.     private final List<Statement>               statementTrace           = new ArrayList<Statement>(2);  
  7. PreparedStatementHolder中呢?new DruidPooledPreparedStatement時,正好用這個holder。  
  8.     private final PreparedStatementKey key;  
  9.     private final PreparedStatement    statement;  


Holder從名字來看就是持有什麼,DruidConnectionHolder必然持有Connection,PreparedStatementHolder必然持有PreparedStatement。DruidConnectionHolder當然還持有屬於這個連線的PreparedStatement之類的。透過幾個呼叫關係,差不多可以猜測出設計思路: 
一般我們用connect物件,再產生statment物件,再執行SQL之類的,當我們在一個物件執行前後做一些統計之類的操作時,那就用代理物件來做,比如前面的filterchain用於代理物件中。可是如果呼叫其它物件時,想把它們之間的一些關聯的東東保持下來,比如一個連線下的所有的PreparedStatement,那就需要一個holder物件來幫忙了。也許你可以把一堆其它的東東都給這個物件身上,不過這樣就不清晰了,太亂了。 
沒準holder也可以稱為一個設計模式。當然proxy也是,還記得有叫handler的吧,都有行為學上的意義!! 
DruidPooledConnection中的PreparedStatement prepareStatement(String sql)方法,就是看看池子裡有沒有(stmtHolder = holder.getStatementPool().get(key);),沒有的話才new PreparedStatementHolder(key, conn.prepareStatement(sql));,有的話記憶體容器中取了。 

大概關係這樣的:DruidPooledConnection-->DruidConnectionHolder-->ConnectionProxy-->filterChain---connection。 

6.講講上面用到的LRU快取,就是存PreparedStatementHolder的池子。 
  一種LinkedHashMap吧,自己實現一下removeEldestEntry方法就可以了,容量達到就扔掉最OLD的。 
Java程式碼  收藏程式碼
  1. public class LRUCache extends LinkedHashMap<PreparedStatementKey, PreparedStatementHolder> {  
  2.     private static final long serialVersionUID = 1L;  
  3.     public LRUCache(int maxSize){  
  4.         super(maxSize, 0.75f, true);  
  5.     }  
  6.     protected boolean removeEldestEntry(Entry<PreparedStatementKey, PreparedStatementHolder> eldest) {  
  7.         boolean remove = (size() > dataSource.getMaxPoolPreparedStatementPerConnectionSize());  
  8.         if (remove) {  
  9.             closeRemovedStatement(eldest.getValue());  
  10.         }  
  11.         return remove;  
  12.     }  
  13. }  


7.MOCK包 
  這個也不太懂,網上查了一下,說是一些造假的,且方便測試的物件,它實現了相關的介面,所以可以被當成它所假冒的東西使用。特別是真實的東西不方便使用,或者很慢,或者有其它不理想的情況下。 

8,sqlPaser 
  druid下的主要的功能包除這個以外,都介紹完了,說是SQL解析器,不過沒空看了,下次看了再補充吧。 

9.connectPool連線池 
  連線池當然是重頭戲了,簡單先提一下,主要用到的是ReentrantLock鎖,還有 notEmpty empty兩個條件,生產連線與消費連線的執行緒在兩個條件上等待與喚醒。連線池是由資料來源確定的,所以具體要看pool包裡的DruidAbstractDataSource與DruidDataSource兩個類了。 
哇,這兩個類很龐大,首先看了一下屬性,主要有很多count,time,還有一些default值,留意集合欄位,比如Map<DruidPooledConnection, Object> activeConnections 
private volatile DruidConnectionHolder[] connections;之類的。裡面還有些執行緒。 
9.1建立連線 
  先看看DruidDataSource裡的CreateConnectionThread都幹什麼,首先是一些條件,比如下面這個程式碼(省略不重要的程式碼),連線太多了的時候,在empty條件上等待,就是等空了再執行,現在別急著建立連線,等著吧! 
// 防止建立超過maxActive數量的連線 
Java程式碼  收藏程式碼
  1.         if (activeCount + poolingCount >= maxActive) {  
  2.             empty.await();  
  3.             continue;  
  4.         }  
  5. try {  
  6.     connection = createPhysicalConnection();  
  7.     setFailContinuous(false);  
  8. boolean result = put(connection);  

後面是建立一個物理連線,然後put一下,這個put很可能是放池子中,那麼仔細看一下。主要下面幾句,說明都寫在後面了: 
    holder = new DruidConnectionHolder(DruidDataSource.this, physicalConnectionInfo);//產生一個連線holder 
            connections[poolingCount] = holder;//這不就是池子嗎?就是一個DruidConnectionHolder的Array了。 
            incrementPoolingCount();//池子中的計數加1. 
            notEmpty.signal();//發出非空的訊號,所有在非空條件上等待的執行緒,你們可能動起來了。 
            notEmptySignalCount++; 
9.2使用連線 
    那麼誰在notEmpty條件上等待呢?我們查一下,發現是方法  DruidConnectionHolder takeLast()之中,當poolingCount中數量為0時等待。正好說明使用連線的執行緒,當連線沒有時,就等待著唄。如果池中有連線呢?就執行下面的語句了: 
        decrementPoolingCount();//減少池中連線的計數,當然拿走一個少一個了。 
        DruidConnectionHolder last = connections[poolingCount];//正好拿走的是池中最後一個。 
        connections[poolingCount] = null;//最後一個就成null了。 
    順便看看誰在用takeLast(),查詢發現是getPooledConnection(),從名字就知道是獲取連結的主要方法了。仔細看看getPooledConnection中又呼叫getConnection(),這裡面又是插入了過濾鏈,果然是為統計而生,都記錄在案了。仔細看filterChain.dataSource_connect()引數中有this,說明它把自己傳進去了,說明這個filterChain並不從屬於任何datasource,可以是這具資料來源,也可以是那個資料來源。具體過濾哪個,臨時傳入。 
    當我們設計過濾鏈時,如果我們的功能是為多人服務的,那就說明要傳入服務物件進來。而不是setpropety設定成關聯關係。一個人如何設計複雜的程式碼呢?當然是頭腦中有一個非常抽象,而明確的思路。 
9.2減少連線 
在建立連線執行緒附近還有一個DestroyConnectionThread(),看看吧 
跟蹤裡面,有destroyTask.run();----->shrink(true);看名字是收縮嘛,可能連線空閒的太多了,就縮小唄。 
在shrink()方法中,重點有下面的語句,分析放在後面: 
final int checkCount = poolingCount - minIdle;//池中的數量-最小空閒數量,感覺是收縮的條件之一嘛。 
Java程式碼  收藏程式碼
  1. for (DruidConnectionHolder item : evictList) {//可回收的都放在這裡了  
  2.     Connection connection = item.getConnection();  
  3.     JdbcUtils.close(connection);//關閉這些連線了。  
  4.     destroyCount.incrementAndGet();  
  5. }  


9.3 初始化方法init() 
都是誰在用這兩個執行緒呢?查詢一下,發現建立執行緒與收縮執行緒是由void init()來呼叫的,看名字就知道這是系統啟動的主方法了。 
void init(){ 
     initFromSPIServiceLoader();//load filters from SPI ServiceLoader,這個spi就不介紹了,在分析dubbo的另一個帖子裡,裡面已經有SPI介紹了。反正是把配置的filter放在filterchain中(List<Filter>) 
Java程式碼  收藏程式碼
  1. connections = new DruidConnectionHolder[maxActive];//新建連線池,個數是最大活動連線數maxActive。  
  2.                 for (int i = 0, size = getInitialSize(); i < size; ++i) {//放入連線池中連線  
  3.                     PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();  
  4.                     DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);  
  5.                     connections[poolingCount] = holder;  
  6.                     incrementPoolingCount();  
  7.                 }  
  8.             createAndLogThread();//看名字是日誌,就不看了  
  9.             createAndStartCreatorThread();//建立連線的執行緒,一直在工作,池子滿了就是等待狀態。  
  10.             createAndStartDestroyThread();//收縮池子的執行緒,一直在工作。  
  11.             initedLatch.await();//主執行緒在計數器為0前一直等待。  
  12.     init = true;  
  13. }  

就裡有一個知識點。CountDownLatch             initedLatch             = new CountDownLatch(2); 就叫倒計時同步器。當前同步數為2,在變成0後,主執行緒才能執行,否則一直等待中。 
在建立連線與收縮池子的執行緒中都有initedLatch.countDown();,一共正好兩個,那麼主執行緒就是等待上面兩個執行緒都運行了才執行吧,才置init狀態標識為true。看來理解沒有錯嘍。 

單看一個create執行緒,裡面有一個countDown方法: 
Java程式碼  收藏程式碼
  1. protected void createAndStartCreatorThread() {  
  2.     if (createScheduler == null) {  
  3.         String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this);  
  4.         createConnectionThread = new CreateConnectionThread(threadName);  
  5.         createConnectionThread.start();  
  6.         return;  
  7.     }  
  8.     initedLatch.countDown();//如果有createScheduler就直接-1;  
  9. }  
  10. public class CreateConnectionThread extends Thread {  
  11.     public void run() {  
  12.         initedLatch.countDown();//如果沒有時,在這裡面-1;  


10。總結: 

看過了原始碼?我們究竟如何提高?我們也可以做出這麼好的東東嗎? 
1.首先你會掌握足夠多的基礎知識,比如會用到多執行緒,concurrent包裡的東西,甚至很少用的容器。說明作者看過很厚的資料書或者看過很多java原始碼。 
2.深入學習國外的原始碼。我發現一些相似的處理方式,在這個產品中出現,在那個產品中也出現,當然不一定完全相同。比如hadoop中的非同步轉同步與dubbo就差不多,什麼 fastfail在秒殺中也有人用。 
3.看過兩個原始碼了,應該可以抽象出處理問題的方式了,這樣自己碰到相似情況時,馬上就可以套用。 
【彩蛋】  
 基本上看完了主要程式碼,為監控而生這句體會更深了,我們就擇其一點,深入體會一下過濾鏈模式吧,算是本貼的彩蛋。這個東東真的很多地方在用,那麼我們如何用呢?使用時,應該有三個物件,分別是被處理的物件,過濾器,過濾器鏈,之前的帖子我提出一個觀點,物件的本質是各種關係的組合,組合是最重要的。那麼這兩個物件之間的包含關係,引用關係,以及主要的方法應該怎麼設計,以及為什麼要這麼設計呢? 
過濾器是一個基本單元,特點是:它不會引用過濾器鏈,因為它可以屬於不同的過濾器鏈。它不會引用處理物件,因為它可以處理這個物件也可以處理那個物件。所以在這三者中,過濾器的過濾方法中,會傳入另外兩個物件,而不會在其它屬性和方法中產生。web中的過濾器中的dofilter引數就是chain與req與res三個。 
過濾鏈一般都是可裝配的,過濾器是一個個基本單元,所以鏈條要給使用者配置的機會,過濾器以後可能會增加,但這個不是給使用者的功能,可以通過spi的機制加進來。 
過濾器鏈條是一個組合器,它的特點:產生過濾器時,必須把基本過濾器傳進來,而且是穩定的引用關係,但因為鏈條上有多個過濾器,所以要有一個容器來放它們。所以過濾鏈持有一個容器,init的時候,放入一個個過濾器。過濾器是串起來一個個執行的,所以還要有一個定位資訊,現在執行到那一個了。再深入思考一下,過濾鏈處理的物件,有的是處理到第2個,有的處理到第5個,有的處理到第3個。那多執行緒的問題來了。查一下程式碼(protected int   pos = 0;if (this.pos < filterSize) donext),看來pos定位計數不是一個threadlocal啊,再看public FilterChainImpl(DataSourceProxy dataSource),建構函式中傳入的是資料來源,所以一個數據源不會傳入計數指標,只會傳過來過濾器容器。回頭我想查一下web中filter的原始碼,裡面的容器是啥,定位是啥?是不是threadlocal變數呢? 
( 補一下,後來在tomcat這裡查到了:org.apache.catalina.core.ApplicationFilterChain的屬性中 private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];  private int pos = 0; 還包含了beforeFilter和afterFilter等功能,作者肯定學習到這些過濾程式碼了,而我too young了,看的東西太少了) 
有點複雜了,再看看FilterChainImpl,裡面並不持有過濾單元,而其中的重要方法,getFilters、nextFilter,都是從構造chain的dataSource中來的。有點象什麼呢?象以前你去找飯店吃飯,現在你帶著菜讓飯店加工。有道理啊,因為過濾鏈規則並不一定要持有基本單位啊,就象氣泡排序不一定持有排序元素,是可以單獨抽象出來的。過濾鏈既然含有非執行緒的pos,那麼每個過濾鏈條都是一次性使用,否則pos指標就亂了。那麼查詢一下工程中所有的new FilterChainImpl(),我們發現pool包裡有4個,其它都在proxy包裡,正好證明了前面說的見縫插針,弄出個代理來,在代理與被代理之間插入過濾鏈,或者其它什麼你想要的功能。比如ClobProxyImpl中有createChain()方法,而且每個clob操作中都要呼叫createChain,就是說每個操作都是新的過濾鏈,那麼前面提到的pos計數就是僅自己方法使用,不會有什麼共享衝突的發生了。 

我們再理一下思路,三個主要的元素(被處理的物件,過濾器,過濾器鏈),其中過濾器鏈被拆分了,只剩下過濾規則與計數器。過濾容器交給了被處理物件持有了,變來料加工。過濾鏈條是每一個proxy物件、準確的說是每一個proxy物件的每一個具體要使用過濾的方法臨時create出來的。再理一個思路,我們看一個filter,看介面與物件都成,發現裡面有處理connect的一大堆方法,有處理resultset的一大堆方法,有處理statemente的一大堆方法,有處理....。 

哇哦,太多了,所有的都在這裡,每一個過濾器都很龐大,很全面,是重量級物件,只有一份。一個數據源持有幾個過濾器,過濾鏈不是細長形狀,而是矮胖形狀的。而你的任何一個物件(當然是代理物件嘍)的任何一個簡單操作,都會生成一個過濾鏈。所以你的過濾鏈中不應該持有過濾器,持有每一個簡單計數pos是非常合理的,過濾鏈是一個輕量級的物件。 

再引申思考一下,如果我們一開始想到一個功能,比如這麼一個監控功能,我們可以肯定的知道用filter方式,我們能否如這般組織好這些物件之間的關係呢?而且這麼組織有沒有什麼進一步重構的可能呢? 
我們可能會有一批與連線相關的過濾器,一批與resultset有關的過濾器;從另一個角度,我們有統計的過濾器,有日誌的過濾器。我們還有過濾鏈規則,我們有很多要過濾的物件,可以先打散,比如過濾鏈的規則與過濾鏈容器是分開的。再嘗試組合,可以按連線來組合(連線的統計,連線的日誌在一起),可以從功能上組合(連線日誌與resultset日誌在一起)。那麼我們插撥的要麼是整個統計,要麼是整個日誌。如果另一種組合,我們可以只要連線的統計與日誌,可以只要查詢的日誌與統計。但如果要連線的統計,要查詢的日誌,那麼druid目前是不支援的。這有點象拆成塊,再搭積木的感覺。 
再比如說,現在由datasource來持有過濾器容器。那麼過濾器的粒度只是不同的資料來源。有些過濾是對connect的,有些是對resultset的,所有的資料來源的下級物件都是一樣的過濾器容器,這方面有沒有個性化的需求呢?比如對clob我只想日誌不想統計,createChain的時候是不是有什麼引數可以配置一下? 

另外,在看FilterChainImpl時,它除了有一大批要過濾的方法外,還有好幾個wrap方法。wrap恰好是根據原始物件來生成過濾縫隙的代理物件,同時把產生filterchain的條件都傳給它,讓代理物件執行每一個方法都可以new filterchain出來。而在代理物件的每一個具體方法中,呼叫filterchain來處理時,又把代理自己給filterchain,filterchain執行過程中,還要用代理物件的getRawObject得到被代理物件來執行最後的業務。如果代理物件連續執行了三個不同的方法,那就是第一次new 一個filterchain,一個鏈條處理完了就會recycleFilterChain(chain);重置pos計數,後面兩個方法就還是用這個代理物件持有的filterchain,不過計數變成0了。 

再理一下:我有一個原始物件,通過FilterChainImpl產生代理物件,代理物件再傳給FilterChainImpl的具體方法用,方法裡面進行過濾後再取出原始物件來用。再比喻:我有一個不鏽鋼杯子,讓別人給包上泥巴,成了一個泥杯子,再讓別人做燒製,著色,刻畫等處理。最後成為精美的陶瓷水杯,當然喝水功能還是靠原來的不鏽鋼杯子來實現的,因為它不是不不鏽鋼菜刀。當然菜刀也可以包上泥巴,也做燒製,著色,刻畫等處理,最後成為一個陶瓷刀具。包泥巴和燒製,著色,刻畫當然是不同的業務,但可以開一個店來做。 

再全面總結一下: 
關於druid,配置一個數據源,它持有一堆過濾器零件,持有一個連線池,連線池裡有兩個主要的執行緒在跑。我對任何物件做任何操作時,給我包裝一下,再產生或重置一個過慮鏈並過濾處理後再執行操作,就醬紫。 


相關推薦

Druid資料連線原始碼分析

Druid是阿里巴巴公司的資料庫連線池工具,昨天突然想學習一下阿里的druid原始碼,於是下載下來分析了一下。也就2個多小時粗略看了一下,中間有些知識點沒見過,不懂,現查BAIDU學習。簡單總結一下,邊總結邊繼續看程式碼,估計錯誤不少,歡迎指正!      在自己看之前,想找找druid原始碼分析,居然在B

Druid資料庫連線原始碼分析

Druid不僅僅是一個數據庫連線池,還有很多標籤,比如統計監控、過濾器、SQL解析等。既然要分析連線池,那先看看DruidDataSource類 getConnection方法的實現:   @Override public DruidPooledConne

idea配置阿里Druid資料連線在SSM框架中使用

阿里Druid資料連線池在SSM框架中的配置使用 一、Druid資料連線池簡介 Druid是Java語言中最好的資料庫連線池。Druid能夠提供強大的監控和擴充套件功能。 效能好,同時自帶監控頁面,可以實時監控應用的連線池情況以及其中效能差的sql,方便我們找出應用中連線池方面的問題。

dbcp BasicDataSource 連線獲取連線過程原始碼分析

通過ibatis,獲取資料庫連線的debug跟蹤如下: 核心指出在於BasicDataSource.getConnection()方法。看下該方法: /** * Create (if necessary) and return a connection

spring下,druid,c3p0,proxool,dbcp四個資料連線的使用和配置

由於那天Oracle的資料連線是隻能使用dbcp的資料庫連線池才連線上了,所以決定試一下當下所有得資料庫連線池連線orcale和mysql,先上程式碼 配置檔案的程式碼 1 #=================dbcp連線池======================# 2 #Oracle資料庫連線

druid 資料庫連線的詳細配置

首先說一下自己程式中遇到的問題,前一段時間新寫了一個專案,主要架構改進,為前端提供介面(spring +springmvc+mybatis) 在新專案中使用的是阿里的druid連線池,配置簡單,除了資料庫地址,驅動類,使用者名稱和密碼其他一起都是預設,開始的時候由於專案更新上線頻率比較多,沒有出現太

JDBC、C3P0、DBCP、Druid 資料來源連線使用的對比總結.md

Java的資料庫連線效能對比 JDBC: jdbc - 全名是 Java data base connectivity;翻譯為 Java資料庫連線 它是一個面向物件的程式介面(API);可以通過它訪問到各類的 關係型資料庫[注意:關係型資料庫] 它不屬於某一個

初識資料連線

什麼是資料連線池? 資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。 為什麼要使用資料連線池? 原因:建立資料庫連線是相當耗時和耗費資

Hive使用druid連線程式碼實現

配置文件 hive_jdbc_url=jdbc:hive2://192.168.0.22:10000/default hive.dbname=xxxxx hive_jdbc_username=root hive_jdbc_password=123456 #配置初始化大小、最小、最大 hiv

web———資料連線的工作機制是什麼?

1.資料庫連線池屬於建立時間昂貴,並且數量有限的資源。如果每次執行sql時都建立新的連線,使用完即刻關閉連線,不僅會造成資源的浪費,而且在併發量大的情況下還會拖慢甚至拖垮資料庫。(測試得出結果單獨執行緒建立資料庫建立時間遠遠大於執行時間) 2. 因此需要使用連線池的概念:預先建立好一批資

DBCP、c3p0、Druid三大連線區別

  DBCP、c3p0、Druid三大連線池區別 一、連線池優勢 如果一個專案中如果需要多個連線,如果一直獲取連線,斷開連線,這樣比較浪費資源; 如果建立一個池,用池來管理Connection,這樣就可以重複使用Connection。 有了池我們就不用自己來建立Connection,而是通

兄弟連區塊鏈教程open-ethereum-pool礦原始碼分析API分析

ApiServer相關定義 type ApiConfig struct { Enabled bool `json:"enabled"` Listen string `json:"listen"` StatsCollectInterval string `json:"statsCollectInterval"

26.以太坊原始碼分析(26)core-txpool交易原始碼分析

txpool主要用來存放當前提交的等待寫入區塊的交易,有遠端和本地的。 txpool裡面的交易分為兩種, 提交但是還不能執行的,放在queue裡面等待能夠執行(比如說nonce太高)。 等待執行的,放在pending裡面等待執行。 從txpool的測試案例來看

阿里Druid資料庫連線配置解釋

#阿里資料庫連線池Druid配置 # 初始化連線大小 spring.datasource.druid.initial-size=20 # 最小空閒連線數 spring.datasource.druid.minIdle=20 # 最大連線數 spring.datasource.druid.maxAct

c3p0,dbcp與druid 三大連線的區別[轉]

說到druid,這個是在開源中國開源專案中看到的,說是比較好的資料連線池。於是乎就看看。扯淡就到這。   下面就講講用的比較多的資料庫連線池。(其實我最先接觸的是dbcp這個)    1)DBCP   DBCP是一個依賴Jakarta commons-pool物件池機制的資料庫連線池.DBCP可以直接的

測試c3p0資料連線的使用----簡單筆記

加入jar包 上程式碼 配置檔案 <c3p0-config> <!-- This app is massive! --> <named-config name="myconfig"> <!-- 設定常用

測試druid資料庫連線併發遇到的問題

測試條件配置: 1:配置druid連線池最大數量為500(maxActive=500)。 2:測試併發量為1000。 報錯:Data source rejected establishment of connection,  message from server: "Too

c3p0,dbcp與druid 三大連線的區別

dbcp連線池pom檔案 <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <vers

Android GATT 連線過程原始碼分析

Android GATT 連線過程原始碼分析   低功耗藍芽(BLE)裝置的通訊基本協議是 GATT, 要操作 BLE 裝置,第一步就是要連線裝置,其實就是連線 BLE 裝置上的 GATT service。 結合上一篇文章,我這裡結合原始碼,分析一下 GATT 連線的流程

基於Druid資料庫連線的資料來源配置,資料庫連線密碼加密解密

Druid的資料庫連線池配置。 <!-- 基於Druid資料庫連線池的資料來源配置 --> <bean id="dataSource" class="com.alibaba.drui