Mybatis中的數據源與連接池

Mybatis中的數據源與連接池

在使用Mybatis框架時需要對核心配置文件進行設置,其中就包括了數據源和連接池。
本文只進行原理的描述,不包含實際代碼。

一、爲什麼要使用連接池?

創建一個Conncection代價是巨大的,因爲創建了一個連接,在底層就與數據庫建立了通信連接,
連接之後往往只進行簡單的sql操作,浪費了巨大的資源。

二、數據庫連接池的基本思想

爲數據庫建立一個“連接池”,預先創建一定數量的連接,當需要連接時,只需從中取出一個,使用
完畢之後再放回。

三、數據源與連接池的描述

1.數據源的分類

(1)UNPOOLED 不使用連接池的數據源
                --用實現了java.sql.DataSource的UnpooledDataSource類來表示
(2)POOLED 使用連接池的數據源
                --用實現了java.sql.DataSource的PooledDataSource類來表示
(3)JNDI 使用JNDI實現的數據源
                --通過JNDI上下文中取值

註釋:PooledDataSource和UnpooledDataSource都實現了java.sql.DataSource接口。
可是當PooledDataSource需要創建java.sql.Connection對象時,是通過UnpooledDataSource來創建的,因爲在PooledDataSource中持有一個UnpooledDataSource的引用,PooledDataSource只是提供一種緩存連接池機制。

2.數據源DataSource的創建過程

Mybatis數據源DataSource對象的創建發生在MyBatis初始化過程中。

(1)Mybatis初始化時,解析xml,根據<datasource>中的type屬性來創建相應類型的DataSource。

註釋:Mybatis創建DataSource根據工廠模式,三種工廠分別是
    UnpooledDataSourceFactory 實現了DataSourceFactory接口
    JndiDataSourceFactory   實現了DataSourceFactory接口
    PooledDataSourceFactory  繼承了UnpooledDataSourceFactory

(2)創建DataSource實例之後,會將實例放入Configuration對象中的Environment對象中。

3.DataSource什麼時候創建Connection對象

創建SqlSession對象執行SQL語句時才調用相應的DataSource來創建Connection對象。
例如執行到sqlSession.selectList("SELECT * FROM STUDENTS");  才創建Connection對象。

4.不使用連接池的UnpooledDataSource

使用UnpooledDataSource的getConnection(),每調用一次就會產生一個新的Connection實例對象。

5.使用了連接池的PooledDataSource

PooledDataSource將Connection對象包裹成PooledConnection對象放入PoolState類型容器中。
Mybatis將PoolConnection分爲兩種狀態:空閒狀態(idle)和活動狀態(active),這兩種狀態
被分別存儲到PoolState容器內的idleConnections和activeConnections兩個List集合中。

idleConnections:idle狀態的PooledConnection放入其中,表示當前沒被使用的連接,需要連接時,優先從中取出。當用完一個Connection對象後,又會被包裹成PooledConnection放到此集合中。

activeConections:active狀態的PoolConnection放入其中,表示正在使用。當需要連接時,優先從idleConnections中取,如果沒有,就看activeConnections集合是否已經滿了,沒滿的話PooledDataSource會創建出一個PooledConnection添加到這個集合中,並返回。

6.獲取java.sql.Connection對象的過程

先看是否有空閒(idle)狀態下的PooledConnection對象,如果有,就直接返回一個可用的PooledConnection對象;否則進行第2步。

查看活動狀態的PooledConnection池activeConnections是否已滿;如果沒有滿,則創建一個新的PooledConnection對象,然後放到activeConnections池中,然後返回此PooledConnection對象;否則進行第3步;

看最先進入activeConnections池中的PooledConnection對象是否已經過期:如果已經過期,從activeConnections池中移除此對象,然後創建一個新的PooledConnection對象,添加到activeConnections中,然後將此對象返回;否則進行第4步。

線程等待,循環2步(代碼見參考資料)

7.java.sql.Connection對象的回收

如何將用完之後的連接自動放回連接池,而不是手動將Connection放到Pool連接池?
所以應該實現Connection對象調用了close()方法,實際上卻是將對象添加到連接池。
這是要使用代理模式,爲真正的Connection對象創建一個代理對象,
代理對象所有的方法都是調用相應的真正Connection對象的方法實現。當代理對象執行close()方法時,
要特殊處理,不調用真正Connection對象的close()方法,而是將Connection對象添加到連接池中。
具體代碼見參考資料。

8.JNDI類型的數據源DataSource

對於JNDI類型的數據源DataSource的獲取就比較簡單,MyBatis定義了一個JndiDataSourceFactory工廠
來創建通過JNDI形式生成的DataSource。具體代碼見參考資料。

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章