如何在Clojure中使用next.jdbc管理数据库连接?
解决Clojure next.jdbc连接耗尽问题
一、评估表单后关闭连接的方法
开发中反复在REPL评估表单导致连接耗尽,核心原因是多次创建独立的连接池实例(每次评估def db-spec都会新建一个HikariDataSource,每个池都占用5个连接)。解决方法如下:
用
let绑定临时连接池,用完即关闭
在REPL中评估查询时,不要定义全局连接池,而是用let创建临时实例,执行完后关闭:(let [db-pool (connection/->pool com.zaxxer.hikari.HikariDataSource {...你的连接配置... :dataSourceProperties {:MaximumPoolSize 5}})] (try (def to-validate (j/execute! db-pool ["select * from raw_data limit 3"])) (finally (.close db-pool)))) ; 关闭连接池,释放所有连接先关闭旧连接池再创建新的
如果必须定义全局连接池,每次评估前先关闭已存在的实例:; 先检查并关闭旧连接池 (when (bound? #'db-spec) (.close db-spec)) ; 重新创建连接池 (def db-spec (connection/->pool com.zaxxer.hikari.HikariDataSource {...你的连接配置... :dataSourceProperties {:MaximumPoolSize 5}})) (def pool (j/get-datasource db-spec))
二、next.jdbc管理连接的最佳实践
1. 全局单例连接池
用defonce替代def定义连接池,确保应用生命周期内只创建一个实例,避免REPL重新加载时重复创建:
(defonce db-spec (connection/->pool com.zaxxer.hikari.HikariDataSource {...你的连接配置... :dataSourceProperties {:MaximumPoolSize 5}})) (defonce pool (j/get-datasource db-spec))
defonce只会在首次定义时初始化,后续评估不会覆盖或重建,从根源避免多连接池占用资源。
2. 自动复用连接,无需手动关闭单个连接
next.jdbc的execute!、query!等函数会自动从连接池获取连接→执行操作→归还连接,不需要手动关闭单个连接。只要连接池是单例的,就不会出现连接泄漏。
3. 封装连接操作,统一管理
在开发环境中,用函数封装数据库操作,确保连接池复用:
(defn close-db-pool [] (when (bound? #'db-spec) (.close db-spec) (alter-var-root #'db-spec (constantly nil)))) (defn get-db-pool [] (or db-spec (def db-spec (connection/->pool com.zaxxer.hikari.HikariDataSource {...你的连接配置... :dataSourceProperties {:MaximumPoolSize 5}})))) (defn fetch-raw-data [] (j/execute! (get-db-pool) ["select * from raw_data limit 3"]))
- 调用
fetch-raw-data会自动复用已有的连接池 - 需要重置连接时,调用
close-db-pool即可释放所有连接
4. 优化连接池配置
给HikariCP添加合理的超时和空闲连接配置,进一步避免连接泄漏:
:dataSourceProperties {:MaximumPoolSize 5 :MinimumIdle 1 ; 保持最少1个空闲连接 :ConnectionTimeout 30000 ; 连接超时时间(30秒) :IdleTimeout 600000 ; 空闲连接回收时间(10分钟) :MaxLifetime 1800000} ; 连接最大生命周期(30分钟)
内容的提问来源于stack exchange,提问作者Vinn
相关产品推荐
相关产品推荐

