(15) Spring Boot 連接至 PostgreSQL 與 HikariCP 的常見使用設定
在上一篇文章中,我們將專案導入了 H2 資料庫,並且透過 Spring Boot 提供的 JDBC Starter 搭配在 Dev 環境 Properties 中設定 spring.datasource
與 H2 資料庫進行連接。
因此本篇文章將會展示如何在 Prod 環境中設定相關參數,又需要導入哪些其他 Dependencies,才可以將專案與 PostgreSQL 進行連線。
不過因為節省資料庫的建置過程,因此本篇文章將會使用一個免費的「PostgreSQL Database Hosting Service」,透過這個服務,我們就可以簡單又快速的建立一個 Database Service 供我們進行連線測試。
不過如果你在你的本機或你的環境中已經有架設好 PostgreSQL,那麼就可以省略這項服務的使用,可以直接參考連線設定的部分即可。
免費的線上 PostgreSQL 服務 - ElephantSQL
這裡廢話不多說 XD,他就是一個有免費方案的線上 PostgreSQL 服務,使用簡單,操作介面方便又直覺,免費方案給的大方,又無需事先綁定信用卡 (這樣就不用怕流量不小新爆掉了),限制的部分整理如下:
- 一個 Instance 最多可以存放 20 MB 的資料
- 一個 Instance 最多可以同時有 5 個 Connections
對於測試來說,這已經非常足夠了。那麼接著我們就來開始創建第一個免費的 Instance 吧!
註冊帳號與建立第一個 Instance
首先要先創建一個帳號,他有支援 Github 與 Google 的 Social login,或者要直接 Sign up 也可以。
接著就可以看到 Instances 的列表,因為才剛建立帳號而已,所以裡面不會有任何東西。
點擊右上方的「Create New Instance」,接著設定 Instance 的名稱。值得注意的是,這裡的名稱只是 Instance 的名稱,而不是資料庫的名稱。另外,在 Plan 的部分預設是 Free 的方案,而其他的方案都是要收費的。
接著要選取 Data Center 的位置,但因為是免費方案,所以可以選擇的位置就會比較少。在這邊我們選取離台灣比較近的「AP-East-1 (Hong Kong)」。
最後再檢查一次內容,沒有問題我們就直接「Create Instance」。頁面跳轉回 Instance 列表頁面,剛剛所建立的 Instance 就會出現在列表中了。
查看 Instance 的相關資訊
(為了做示範,在這裡我的連線資訊全部都會以明碼顯示,但是我會在範例結束之後刪除這個 Instance)
從列表點擊對應的 Instance 後,就會進入到 Details 的頁面。
在 Details 頁面中你就可以看到這個資料庫的基本資訊。ElephantSQL 預設是將 Database 的名稱與連線許可的名稱視為同一個值。而 URL 的部分則是像 postgres://[username]:[password]@[hostname]/[databasename]
這樣的格式來表示,對應的結果就為:
- username: aeafcpwv
- password: izbnpJkJ3_aaEhcSkbB5pUNaa5mq8rjn
- hostname: john.db.elephantsql.com:5432
- databasename: aeafcpwv
其他功能
在左邊有其他的頁面可以進入,只是如果是使用免費的 Instance 的話,那麼會有一些頁面是沒有權限可以造訪的。
在免費版中,可以進入的頁面有:
- Detail:資料庫的連線相關細節
- Browser:使用 SQL Query 的頁面
- Stats:查看資料庫的連線狀態,像是連接數量與連接位置
- Slow Query:顯示 SQL Query 的時間以及相關細節
- Backup:備份這個 Instance 的資料
那麼 ElephantSQL 的部分就暫時先介紹到這邊,不過應該可以發現,他的操作介面實在非常簡單又直覺,也因此如果需要一個資料庫來進行測試且資料量不大的話,ElephantSQL 應該可以算是個不錯的選擇。
JDBC 連接至 PostgreSQL
現在我們得到一個遠端的 PostgreSQL 服務,接著要將專案進行設定,並且將專案連到這個 PostgreSQL 的遠端服務。
在上一篇文章中,我們是在 Dev 環境的 Properties 內,對 spring.datasource的相關設定值指向 H2 Database。因此現在在這一篇文章中,我們可以改為在 Prod 的環境中加上與 PostgreSQL 的相關連線設定值。
根據在 ElephantSQL 的 Detail 頁面中的資訊,我們可以進行如下設定:
spring:
datasource:
url: jdbc:postgresql://john.db.elephantsql.com:5432/aeafcpwv
username: aeafcpwv
password: izbnpJkJ3_aaEhcSkbB5pUNaa5mq8rjn
接著以 Prod 的 Properties 啟動專案
.\mvnw -P prod
其中可以看到 HikariCP 的相關訊息,這代表著 Hikari 在建立 Connection Pool (別忘了,Spring Boot 預設所使用的 Connection Pool 就是 Hikari):
INFO [main] HikariDataSource: HikariPool-1 - Starting...
INFO [main] HikariDataSource: HikariPool-1 - Start completed.
接著我們可以到 ElephantSQL 的 STATS 頁面檢查連線狀態:
由於免費版的 Instance 可以允許的連線數量是 5 個,在 Application Name 的欄位上,第一列顯示「elephantsql-stream」,這是因為在建立 Instance 後,ElephantSQL 會需要佔據一個連線位置,以提供與事件或訊息之間的溝通。
而下方的四個連線,就是透過 HikariCP 所建立的 Connection Pool。但其實 HikariCP 所建立的 Connection Pool 並不只有四個而已。可以在 HikariCP 的 Github 中找到 maximumPoolSize
的相關訊息,他的預設值為 10,所以在不設定任何參數的情況下,HikariCP 所建立的 Connection Pool 的數量是 10 個。
如果想要修改連線數量,可以像下方這樣設定,假設我只要建立 3 個 Connection Pool:
spring:
datasource:
url: jdbc:postgresql://john.db.elephantsql.com:5432/aeafcpwv
username: aeafcpwv
password: izbnpJkJ3_aaEhcSkbB5pUNaa5mq8rjn
hikari:
maximum-pool-size: 3
那麼在 ElephantSQL 的 STATS 頁面中,就可以看到只有建立 3 個連線了。
Idle 是甚麼
Idle,形容詞,閒置的。在上圖中可以看到在 Stats 的欄位,狀態都是 Idle,代表他的連線狀態是閒置的,那為什麼會需要閒置的連線呢?
還記得在建立 Connection Pool 的目的就是在於「當有需要使用連線的時候就可以從 Connection Pool 中取得 Connection」,而這些 Connection 要可以「隨取即用」就必須要讓 Connection 保持「長連接」的狀態,或者說是「Keep Alive」。
要讓連線是長連接的狀態就必須要在建立 TCP 連線後,相互的定時通知對方說「欸欸!我還活著喔!不要斷掉了!」,這個傳送的內容,就叫做「Heartbeat Packet」,或者稱他為「心跳包」。
可是在這樣頻繁的送心跳包的過程中,也都是需要對心跳包做編碼與解碼,因此多少來是會浪費系統資源,因此 Idle 機制就出現了。Idle 機制算是心跳包的機制優化,為了避免相互的、定時的持續送出心跳包,那麼只要在服務端去監聽客戶端對服務端的讀寫時間,並定期的去跟客戶端確認連線狀態,如此一來,就可以用相對少的資源來達到長連接的機制了。
之所以會先介紹 Idle,主要是因為後續在 Hikari 的設定值中,有相關的參數可以進行設定,因此先介紹過甚麼是 Idle Connection 以及 Idle Timeout 會對於後續的了解內容有幫助。
Hikari 的常用的參數設定
如果仔細的參考 Hikari Github 上的說明,裡頭有提到一些比較常用的設定,這裡我們稍微簡單的帶過 (以下 Connection Pool 都會以「連線池」表示):
poolName
可以設定連線池的名稱,主要的作用在於可以在 Console 或者 Print Log 的時候,能夠顯示自定義的連線池的名稱。
maximumPoolSize
設定 Hikari 建立連線池內 Connection 的最大數量。而這個值的設定其實應該依照你的執行環境,例如硬體性能。此外,如果設定的值超過資料庫所許可的連線數量,那麼連線池內的數量就會依照許可連線數而定。
autoCommit
設定是否要自動 Commit SQL Command,預設值為 true。如果 autoCommit 的值為 true,那麼只要在使用這些 Connect 的 Statement 或 Session 去操作資料庫,例如新增、修改、刪除等命令都會被自動提交,如果不小心發生邏輯錯誤,那麼所提交出去的命令也就無法挽回了。
但如果 autoCommit 的值設定為 false,那麼則必須明確的在商業邏輯後提交所使用到的命令後才會使 Commit 生效,而在商業邏輯中若發生錯誤,則可以使用 Rollback 來回復在發生錯誤之前的狀態。為了避面錯誤發生時無法返回狀態,也因此我們通常會將此值設定為 false,像這樣:
spring:
datasource:
hikari:
auto-commit: false
connectionTimeout
當從連線池拿取 Connection 時,卻發現 Connection 的數量已達上限,那麼就會等待一段時間,如果在這段時間內都沒有 Connection 可以從連線池中取得,那麼就會發生 SQLException 的錯誤。而這段等待時間的最大許可值就是 connectTimout,其預設值為 30000,也就是 30 秒。
minimumIdle
這個值可以控制 Idle Connection 的最小數量,但這個值的預設值會取決於 maximumPoolSize 的大小。若 minimumIdle 的數量小於 maximumPoolSize ,那麼在建立連線池的步驟就會像這樣:
- 先建立 minimumIdle 數量的 Idle Connection 於連線池中
- 應用程式向連線池拿取 Connection
- 當拿取 Connection 的數量大於 minimumIdle 時,Hikari 會建立更多的 Connection 於連線池中,直到連線池內的數量為 maximumPoolSize 為止
- 當連線池中的 Idle Connection 所閒置的時間超過 idleTimeout,則關閉連線,直到連線池內的數量為 minimumIdle 為止
這個值代表如果設定這個值,則會讓連線池的數量不固定,並且會造成額外開啟連線與關閉連線所需的資源。因此除非是在其他特定需求的情況下,否則這個值我們就會不設定他,讓他是預設值,也就是 maximumPoolSize,即可。
idleTimeout
這個值的說明可以看 minimumIdle 部分的說明。而 idleTimeout 的設定也只有在 minimumIdle < maximumPoolSize 的情況下才有作用。
maxLifetime
這個值在官方網站的說明中是「強烈建議使用的值」。這個值主要用來設定在連線池的 Connection 所能存活的最大時間。當 Connection 存活的時間到達了 maxLifetime,那麼這個 Connection 就會被關閉,然後再重新建立一個新的 Connection 於連線池中。
之所以會這麼做的原因是為了要避免 mass-extinction 的發生,同時也可以避免堆積過多的 Garbage 等待 GC 回收,造成 GC 回收時間過久,導致系統發生異常。
詳細說明可以參考: https://juejin.cn/post/6844904146915557389
connectionTestQuery
這是連線池在建立前,會先執行此值所設定的 SQL 命令。官方建議如果是使用 JDBC4 的 Driver,那麼最好不要設定此值。
文末
上一篇文章中,我們在 Dev 環境中將應用程式與 H2 DB 連接。而在本篇中,我們則是在 Prod 環境中將應用程式與 PostgreSQL 進行連接,並且使用線上的免費資源 ─ ElephantSQL 來進行測試。
中間有稍微提到了一下 Keep Alive 的實現機制,並簡單的介紹了一下甚麼是 Idle Connection。而最後則是介紹了 Hikari 的一些常用設定值。
在下一篇開始,我們就要開始將資料庫建立 Table,但是在那之前會先介紹資料庫的版本管理工具 ─ Liquibase,透過 Liquibase 來協助我們避免直接寫 SQL Command 來新增、修改、刪除 Table 的相關動作,並簡介資料庫版本控管的相關細節。
前往
本篇程式碼
上一篇
下一篇
所有文章列表