Druid是阿里巴巴的一個數據庫鏈接池開源框架,準確來講它不單單包括數據庫鏈接池這麼簡單,它還提供強大的監控和擴展功能。本文僅僅是在不採用Spring框架對Druid的窺探,採用目前最新版本druid1.0.26 github地址:https://github.com/alibaba/druid。java
在開始以前仍是再說說爲何不配套使用Spring來使用Druid鏈接池,緣由其實很簡單,在Spring框架的配置文件中僅僅一個配置datasource就可使用Druid了。那到底配置這個datasource數據源時Spring到底對它作了什麼呢?它究竟是怎麼來實現這個datasource數據源的呢?若是不知其二隻知其一,那才真是隻是個搬磚的。mysql
下面咱們正式開始吧,首先仍是一覽工程包結構。git
一樣有兩個jar須要引入,一是druid,二是mysql-connector。github
咱們首先實現util包裏的DBPoolConnection類,這個類用來建立數據庫鏈接池單例以及返回一個數據庫鏈接。爲何數據庫鏈接池須要單例呢?緣由其實很簡單,咱們能夠想象在一個web應用中,同時可能會存在多個請求若是爲每個請求都建立一個數據庫鏈接池,那還有什麼意義呢?應該是不論有多少個併發請求,都應該只存在一個數據庫鏈接池,在這個數據庫鏈接池中爲每一個請求建立一個數據庫鏈接。web
1 package util; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.InputStream; 6 import java.sql.SQLException; 7 import java.util.Properties; 8 9 import com.alibaba.druid.pool.DruidDataSource;10 import com.alibaba.druid.pool.DruidDataSourceFactory;11 import com.alibaba.druid.pool.DruidPooledConnection;12 13 /**14 * 要實現單例模式,保證全局只有一個數據庫鏈接池15 * @author ylf16 *17 * 2016年10月21日18 */19 public class DBPoolConnection {20 private static DBPoolConnection dbPoolConnection = null;21 private static DruidDataSource druidDataSource = null;22 23 static {24 Properties properties = loadPropertiesFile("db_server.properties");25 try {26 druidDataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties); //DruidDataSrouce工廠模式27 } catch (Exception e) {28 e.printStackTrace();29 }30 }31 32 /**33 * 數據庫鏈接池單例34 * @return35 */36 public static synchronized DBPoolConnection getInstance(){37 if (null == dbPoolConnection){38 dbPoolConnection = new DBPoolConnection();39 }40 return dbPoolConnection;41 }42 43 /**44 * 返回druid數據庫鏈接45 * @return46 * @throws SQLException47 */48 public DruidPooledConnection getConnection() throws SQLException{49 return druidDataSource.getConnection();50 }51 /**52 * @param string 配置文件名53 * @return Properties對象54 */55 private static Properties loadPropertiesFile(String fullFile) {56 String webRootPath = null;57 if (null == fullFile || fullFile.equals("")){58 throw new IllegalArgumentException("Properties file path can not be null" + fullFile);59 }60 webRootPath = DBPoolConnection.class.getClassLoader().getResource("").getPath();61 webRootPath = new File(webRootPath).getParent();62 InputStream inputStream = null;63 Properties p =null;64 try {65 inputStream = new FileInputStream(new File(webRootPath + File.separator + fullFile));66 p = new Properties();67 p.load(inputStream);68 } catch (Exception e) {69 e.printStackTrace();70 } finally {71 try {72 if (null != inputStream){73 inputStream.close();74 }75 } catch (Exception e) {76 e.printStackTrace();77 }78 }79 80 return p;81 }82 83 }
第26行代碼實例化一個DruidDataSource時,咱們能夠經過Druid框架爲咱們提供的DruidDataSourceFactory建立出一個DruidDataSource實例,工廠模式給咱們提供了大大的便利。spring
第36行getInstance方法爲咱們建立出一個數據庫鏈接池實例,這裏即用到了單例模式,在這個地方咱們可使用synchronized方法來對getInstance加鎖(懶加載)實現線程安全,同時咱們也可使用勤加載來實現線程安全即去掉synchronized關鍵字,刪掉37-39行代碼,將第20行代碼修改成private static DBPoolConnection dbPoolConnection = new DBPoolConnection()。這兩種方式各有其優缺點,懶加載好處就是「用到才實例化」,缺點就是「synchronized關鍵字對方法加鎖的粒度稍稍有點大,採用同步的方式實現線程安全會帶來額外的開銷」,而勤加載的好處就是「不使用同步的方式實現線程安全,省去了同步機制帶來的額外開銷」,缺點便是「未用到也會實例化」。至於怎麼選擇,根據實際狀況。這裏是以前對單例模式的兩篇博文,《單例模式》、《再說單例模式的線程安全問題》。sql
第55行代碼loadPropertiesFile方法是對properties配置文件的加載。數據庫
咱們在這個類所作的工做差很少就是在spring配置文件中的那一句<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">。很簡單的一句話,這就是爲何我不想使用Spring框架來配合使用Druid,由於這隻會形成只知其一不知其二的結果。安全
咱們接在來實現dao包中的DruidDao類,開始對數據進行持久化操做。因爲咱們沒有用到MyBatis等持久層框架,因此咱們不得不使用JDBC來操做數據庫,雖然麻煩一點,但這是全部全部框架的基礎。併發
1 /** 2 * 3 */ 4 package dao; 5 6 import java.sql.PreparedStatement; 7 import java.sql.SQLException; 8 9 import com.alibaba.druid.pool.DruidPooledConnection;10 11 import util.DBPoolConnection;12 13 /**14 * @author ylf15 *16 * 2016年10月21日17 */18 public class DruidDao {19 20 public void insert(String sql){21 DBPoolConnection dbp = DBPoolConnection.getInstance(); //獲取數據鏈接池單例22 DruidPooledConnection conn = null;23 PreparedStatement ps = null;24 try {25 conn = dbp.getConnection(); //從數據庫鏈接池中獲取數據庫鏈接26 ps = conn.prepareStatement(sql);27 ps.executeUpdate();28 } catch (SQLException e) {29 e.printStackTrace();30 } finally {31 try {32 if (null != ps){33 ps.close();34 }35 if (null != conn){36 conn.close();37 }38 } catch (Exception e) {39 e.printStackTrace();40 }41 }42 }43 }
咱們只對數據作插入操做。下面咱們測試一下,各個屬性的含義可參考:https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8
1 /** 2 * 3 */ 4 package test; 5 6 import dao.DruidDao; 7 8 /** 9 * @author ylf10 *11 * 2016年10月21日12 */13 public class Client {14 15 /**16 * @param args17 */18 public static void main(String[] args) {19 DruidDao druidDao = new DruidDao();20 String sql = "insert into test (name) values(\"keven\")";21 druidDao.insert(sql);22 }23 24 }
查看數據庫插入成功。
另外db_server.properties數據庫的配置文件以下:
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/DruidTestusername=root password=0000filters=stat initialSize=2maxActive=300maxWait=60000timeBetweenEvictionRunsMillis=60000minEvictableIdleTimeMillis=300000validationQuery=SELECT 1testWhileIdle=truetestOnBorrow=falsetestOnReturn=falsepoolPreparedStatements=falsemaxPoolPreparedStatementPerConnectionSize=200