下面會詳細介紹一種最實用的數據庫鏈接池的詳細介紹及其使用------德魯伊(druid)java
通過上面的介紹,咱們須要建立一個鏈接池,以供咱們鏈接數據庫操做,在沒用鏈接池以前,用戶訪問數據庫的時候都是本身建立鏈接對象的。
mysql
咱們使用了鏈接池以後:從系統開始啓動的時候就會建立一個工廠對象,裏面有必定數量的數據庫鏈接對象,用戶使用的時候直接會從池子裏拿鏈接對象,不須要本身在建立了。
git
鏈接池解決現狀問題的原理github
Connection鏈接對象 | 操做特色 |
---|---|
建立時 | 鏈接對象再也不由本身建立,而是系統啓動的時候已經建立必定數量的鏈接, 而且放在鏈接池中 |
使用時 | 直接從鏈接池中去獲取一個已經建立好的鏈接對象便可 |
關閉時 | 不是真的關閉鏈接對象,而是將鏈接對象再放回到鏈接池中,供下一個用戶使用 |
數據源接口中的方法:sql
DataSource接口中的方法 | 描述 |
---|---|
Connection getConnection() | 從鏈接池中獲取鏈接對象 |
每一個鏈接池都會有不少的參數,每一個參數都有不一樣的含義,幾乎全部的參數都是由默認值的,參數名在不一樣的鏈接池中表明的意思也有所差別!數據庫
經常使用參數 | 描述 |
---|---|
初始鏈接數 | 服務器啓動的時候建立的鏈接對象數量 |
最大鏈接數 | 鏈接池中最多能夠容許放多少個鏈接對象 |
最長等待時間 | 若是鏈接池中沒有鏈接對象,設置用戶等待的最長時間是多久,單位是毫秒。 若是超過這個時間就拋出異常 |
最長空閒回收時間 | 若是一個鏈接對象長時間沒有人使用,設置多久回收這個對象,默認是不回收。 |
DataSource自己是Oracle公司提供的一個接口,自己沒有具體的實現,它的實現由各大鏈接池的數據庫廠商去實現,咱們只須要學習如何使用就ok了。服務器
經常使用的鏈接池組件:ide
Druid是阿里巴巴開發的號稱爲監控而生的數據庫鏈接池,在功能、性能、擴展性方面,都超過其餘數據庫鏈接池。Druid已經在阿里巴巴部署了超過600個應用,通過一年多生產環境大規模部署的嚴苛考驗。如:一年一度的雙十一活動,每一年春運的搶火車票。工具
Druid的下載地址:https://github.com/alibaba/druid性能
DRUID鏈接池使用的jar包:druid-1.0.9.jar
參數 | 說明 |
---|---|
url | 鏈接字符串 |
username | 用戶名 |
password | 密碼 |
driverClassName | 驅動類名,會自動根據URL識別,這一項能夠不配置 |
initialSize | 初始鏈接數 |
maxActive | 最大鏈接數 |
maxWait | 最長等待時間 |
Druid鏈接池API介紹
Class類中的方法 | 說明 |
---|---|
InputStream getResourceAsStream(String path) | 加載類路徑下配置文件,轉成一個輸入流對象 |
DruidDataSourceFactory的方法 | 方法 |
---|---|
public static DataSource createDataSource(Properties properties) | 經過屬性集合中屬性,建立一個鏈接池 |
導包:
.properties配置文件:
url=jdbc:mysql://localhost:3306/test username=root password=root driverClassName=com.mysql.jdbc.Driver initialSize=5 maxActive=10 maxWait=2000
java代碼:
public class Demo2Druid { public static void main(String[] args) throws Exception { //1.從類路徑下加載配置文件,獲取一個輸入流。若是不指定路徑,默認是讀取同一個包下資源文件 InputStream inputStream = Demo2Druid.class.getResourceAsStream("/druid.properties"); //2.使用Properties對象的方法將配置文件中屬性加載到Properties對象中 Properties properties = new Properties(); //加載了配置文件中全部的屬性 properties.load(inputStream); //3.經過druid的工廠類建立鏈接池 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); //獲取10個鏈接對象 for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println("第" + i + "個鏈接對象:" + connection); //第3個鏈接關閉 if (i==3) { connection.close(); } } } }
可是若是超過了數據庫最大鏈接數量:
可是咱們讓第三個關閉了鏈接,至關於還給鏈接池一個鏈接對象,因此會打印是以個結果:(有兩個地址值是相同的!)
使用Druid鏈接池來獲取鏈接對象,達到提高訪問數據庫速度目的
package com.aoshen.Test; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; public class JDBCUtils { //聲明鏈接池對象 private static DataSource dataSource; //使用靜態,是類加載的時候就建立鏈接池 static{ try { //讀取配置文件 InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid"); //獲取Properties對象,加載到該對象中 Properties properties = new Properties(); //獲取配置文件 properties.load(inputStream); //建立druid工廠 dataSource = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } //獲取數據庫鏈接 public static Connection getConn() throws SQLException { return dataSource.getConnection(); } /** * 關閉鏈接 * 查詢調用這個方法 */ public static void close(Connection connection, Statement statement, ResultSet resultSet) { try { if (resultSet != null) { resultSet.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (statement != null) { statement.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (connection != null) { connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } /** * 關閉鏈接 * 增刪改沒有結果集 */ public static void close(Connection connection, Statement statement) { //直接調用上面的方法 close(connection, statement, null); } /** * 通用的增刪改方法 */ public static int update(String sql,Object...args){ Connection conn = null; PreparedStatement ps = null; //返回影響的行數 int row = 0; try{ //獲取鏈接 conn = getConn(); //獲取預編譯對象 ps = conn.prepareStatement(sql); //獲取元數據,獲得有多少佔位符 ParameterMetaData metaData = ps.getParameterMetaData(); int count = metaData.getParameterCount(); //循環獲取賦值 for (int i = 0; i < count; i++) { ps.setObject(i+1,args[i]); } //執行SQL語句 row = ps.executeUpdate(); }catch (Exception e){ e.printStackTrace(); }finally { close(conn,ps); } return row; } /** * 通用的查詢方法 */ public static <T> List<T> equery(String sql,Class<T>c,Object...args){ Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; //建立集合用於接收數據庫中查的值 List<T>list = new ArrayList<>(); try{ //獲取鏈接 conn = getConn(); //獲取預編譯對象 ps = conn.prepareStatement(sql); //經過獲取元數據給佔位符賦值 ParameterMetaData metaData = ps.getParameterMetaData(); int count = metaData.getParameterCount(); for (int i = 0; i < count; i++) { ps.setObject(i+1,args[i]); } //執行sql rs = ps.executeQuery(); //遍歷集合,封裝到集合中嗎,一行數據封裝一個對象 while (rs.next()){ //每條記錄封裝成一個對象 T t = c.newInstance(); //獲得實體類中有哪些列名 Field[] fields = c.getDeclaredFields(); //遍歷賦值 for (Field field : fields) { //獲取列名 String name = field.getName(); //獲取內容 Object value = rs.getObject(name); //由於是私有的,要暴力反射 field.setAccessible(true); //把最後獲得的值賦值給建立的對象中 field.set(t,value); } //把最後含每一行值的對象添加到集合中 list.add(t); } }catch (Exception e){ e.printStackTrace(); }finally { close(conn,ps,rs); } return list; } }
使用工具類
/** * 使用工具類 */ public class Demo3UseUtils { public static void main(String[] args) { //使用工具類添加1條記錄 int row = JdbcUtils.update("insert into student values(null,?,?,?)", "嫦娥", 0, "1997-07-07"); System.out.println("添加了" + row + "條"); //使用工具類查詢全部的數據 List<Student> students = JdbcUtils.query("select * from student", Student.class); //打印 students.forEach(System.out::println); } }
修改了鏈接的獲取方式