池化思想是我們項目開發過程中的一種非常重要的思想,如整數池,字元串池,對象池、連接配接池、線程池等都是池化思想的一種應用,都是 通過複用對象,以減少因建立和釋放對象所帶來的資源消耗,進而來提升系統性能。 例如Integer對象的内部池應用。
package com.cy.java.pool;
public class TestInteger01 {
public static void main(String[] args) {
Integer n1=100;//Integer.valueOf(100) 編譯時優化
Integer n2=100;
Integer n3=200;
Integer n4=200;//池中沒有則new Integer(200)
System.out.println(n1==n2);//true
System.out.println(n3==n4);//false
}
}
這就是因為Intrger對象維護了一個常量池,相同資料不再開辟空間存儲區間是-128--127。
連接配接池原理在系統初始化的時候,在記憶體中開辟一片空間,将一定數量的資料庫連接配接作為對象存儲在對象池裡,并對外提供資料庫連接配接的擷取和歸還方法。使用者通路資料庫時,并不是建立一個新的連接配接,而是從資料庫連接配接池中取出一個已有的空閑連接配接對象;使用完畢歸還後的連接配接也不會馬上關閉,而是由資料庫連接配接池統一管理回收,為下一次借用做好準備。如果由于高并發請求導緻資料庫連接配接池中的連接配接被借用完畢,其他線程就會等待,直到有連接配接被歸還。整個過程中,連接配接并不會關閉,而是源源不斷地循環使用,有借有還。資料庫連接配接池還可以通過設定其參數來控制連接配接池中的初始連接配接數、連接配接的上下限數,以及每個連接配接的最大使用次數、最大空閑時間等,也可以通過其自身的管理機制來監視資料庫連接配接的數量、使用情況等。
java中的連接配接池Java官方,為了在應用程式中更好的應用連接配接池技術,定義了一套資料源規範,例如javax.sql.DataSource接口,基于這個接口,很多團隊或個人建立了不同的連接配接池對象。然後我們的應用程式中通過耦合與DataSource接口,便可以友善的切換不同廠商的連接配接池。Java項目中通過連接配接池擷取連接配接的一個基本過程,如下圖所示:
在上圖中,使用者通過DataSource對象的getConnection()方法,擷取一個連接配接。假如池中有連接配接,則直接将連接配接傳回給使用者。假如池中沒有連接配接,則會調用Dirver(驅動,由資料庫廠商進行實作)對象的connect方法從資料庫擷取,拿到連接配接以後,可以将連接配接在池中放一份,然後将連接配接傳回給調用方。連接配接需求方再次需要連接配接時,可以從池中擷取,用完以後再還給池對象。
資料庫連接配接池在Java資料庫相關中間件産品群中,應該算是底層最基礎的一類産品,作為企業應用開發必不可少的元件,無數天才們為我們貢獻了一個又一個的優秀産品,它們有的随時代發展,功成身退,有的則還在不斷疊代,老而彌堅,更有新生代産品,或性能無敵,或功能全面。目前市場上常見的連接配接池有DBCP、C3P0,DRUID,HikariCP等。
SpringBoot工程下HikariCP整合測試 資料初始化打開mysql控制台,然後按如下步驟執行goods.sql檔案。
第一步:登入mysql。
mysql –uroot –p1234
第二步:設定控制台編碼方式。
set names utf8;
第三步:執行goods.sql檔案(切記不要打開檔案複制到mysql用戶端運作)。
source d:/goods.sql
其中goods.sql檔案内容如下:
drop database if exists dbgoods;
create database dbgoods default character set utf8;
use dbgoods;
create table tb_goods(
id bigint primary key auto_increment,
name varchar(100) not null,
remark text,
createdTime datetime not null
)engine=InnoDB;
insert into tb_goods values (null,'java','very good',now());
insert into tb_goods values (null,'mysql','RDBMS',now());
insert into tb_goods values (null,'Oracle','RDBMS',now());
insert into tb_goods values (null,'java','very good',now());
insert into tb_goods values (null,'mysql','RDBMS',now());
insert into tb_goods values (null,'Oracle','RDBMS',now());
insert into tb_goods values (null,'java','very good',now());
建立項目Module并添加相關依賴第一步:基于IDEA建立項目Module,如圖所示:
SpringBoot-整合HikariCP連接配接池
第二步:添加依賴
- mysql資料庫驅動依賴。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- spring對象jdbc支援(此時會預設幫我們下載下傳HiKariCP連接配接池)。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
配置HikariCP連接配接池打開application.properties配置檔案,添加如下内容(必寫)。
#spring datasource
spring.datasource.url=jdbc:mysql:///dbgoodsserverTimezone=GMT%2B8&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=1234
hikariCP 其它額外配置(可選),代碼如下(具體配置不清晰的可自行百度):
spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=DatebookHikariCP spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-test-query=SELECT 1
HikariCP 連接配接池測試單元測試API設計及應用分析,如圖所示:
在項目中添加單元測試類及測試方法,代碼如下:
package com.cy.pj.common.datasource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
@SpringBootTest public class DataSourceTests {
@Autowired
private DataSource dataSource; //interface
@Test
public void testConnection() throws Exception{
//通過datasource擷取連接配接的一個過程是怎麼樣的 System.out.println(dataSource.getConnection()); //[email protected] wrapping [email protected]
}
}
在目前測試類中我們需要:
- 掌握單元測試類、測試方法編寫規範。
- 了解DataSource的設計規範及規範的實作。
- 分析在測試類中dataSource屬性指向的對象是誰?
- 分析在測試類中DataSource的實作類對象由誰建立和管理?
- 思考基于DataSource接口擷取連接配接的基本過程是怎樣的?
基于HikariCP,借助JDBC技術通路商品庫中的資料。
API架構設計基于業務,進行API設計,如圖所示:
業務時序圖分析基于業務需求,進行商品查詢過程的的時序圖設計,如圖所示:
業務代碼設計及實作第一步:定義GoodsDao接口,例如:
package com.cy.pj.goods.dao;
import java.util.List;
import java.util.Map;
public interface GoodsDao {
List<Map<String,Object>> findGoods();
}
第二步:建立GoodsDao接口實作類,代碼如下:
package com.cy.pj.goods.dao;
@Repository
public class DefaultGoodsDao implements GoodsDao{
@Autowired private DataSource dataSource;//hikariCP
public List<Map<String,Object>> findGoods(){
Connection conn=null;//java.sql.*
Statement stmt=null;
ResultSet rs=null;
String sql="select * from tb_goods";
//1.擷取連接配接(從連接配接池擷取)
try {
conn=dataSource.getConnection();
//2.建立statement對象
stmt=conn.createStatement();
//3.發送sql
rs=stmt.executeQuery(sql);
//4.處理結果
List<Map<String,Object>> list=new ArrayList<>();
while(rs.next()){//循環一次取一行,一行記錄映射為一個map對象
list.add( rowMap(rs));//将存儲了一行記錄的map對象再存儲到list集合
}
return list; }catch (SQLException e){
e.printStackTrace();
throw new RuntimeException(e);//轉換為非檢查異常(編譯時不檢測的異常)
}finally{
//5. 釋放資源
close(rs,stmt,conn);
}
}
定義行映射方法
private Map<String,Object> rowMap(ResultSet rs)throws SQLException{
Map<String,Object> rowMap=new HashMap<>();
//方法1映射
//rowMap.put("id",rs.getInt("id"));
//rowMap.put("name",rs.getString("name")); //rowMap.put("remark",rs.getString("remark")); //rowMap.put("createdTime",rs.getTimestamp("createdTime"));
//方法2映射
ResultSetMetaData rsmd=rs.getMetaData();//擷取中繼資料(包括表中的字段名)
int columnCount=rsmd.getColumnCount();//擷取列的數量
for(int i=0;i<columnCount;i++){ rowMap.put(rsmd.getColumnLabel(i+1),rs.getObject(rsmd.getColumnLabel(i+1)));
//getColumnLabel(i+1);擷取表中字段名或字段名對應的别名
}
return rowMap;
}
定義釋放資源的方法
private void close(ResultSet rs,Statement stmt,Connection conn){ if(rs!=null)try{rs.close();}catch(Exception e){e.printStackTrace();} if(stmt!=null)try{stmt.close();}catch(Exception e){e.printStackTrace();} //這裡的連接配接是傳回到了池中
if(conn!=null)try{conn.close();}catch(Exception e){e.printStackTrace();}
}
}
測試代碼的編寫及運作定義單元測試類,并對其查詢過程進行單元測試,例如:
package com.cy.pj.goods.dao;
@SpringBootTest
public class GoodsDaoTests {
@Autowired
private GoodsDao goodsDao;
@Test
void testFindGoods(){
List<Map<String,Object>> list= goodsDao.findGoods();
for(Map<String,Object> map:list){
System.out.println(map);
}
}
}
測試運作過程中的BUG分析對測試過程中出現的問題進行記錄,分析,總結.
總結(Summary)總之,資料庫連接配接池的為我們的項目開發及運作帶來了很多優點,具體如下:
- 資源重用更佳。
由于資料庫連接配接得到複用,減少了大量建立和關閉連接配接帶來的開銷,也大大減少了記憶體碎片和資料庫臨時程序、線程的數量,使得整體系統的運作更加平穩。
- 系統調優更簡便。
使用了資料庫連接配接池以後,由于資源重用,大大減少了頻繁關閉連接配接的開銷,大大降低了TIME_WAIT的出現頻率。
- 系統響應更快。
資料庫連接配接池在應用初始化的過程中一般都會提前準備好一些資料庫連接配接,業務請求可以直接使用已經建立的連接配接,而不需要等待建立連接配接的開銷。初始化資料庫連接配接配合資源重用,使得資料庫連接配接池可以大大縮短系統整體響應時間。
- 連接配接管理更靈活。
資料庫連接配接池作為一款中間件,使用者可以自行配置連接配接的最小數量、最大數量、最大空閑時間、擷取連接配接逾時間、心跳檢測等。另外,使用者也可以結合新的技術趨勢,增加資料庫連接配接池的動态配置、監控、故障演習等一系列實用的功能。