下载工作台
Go 数据库实战

sqlx 与连接池配置

试读上半部分 · 解锁后可读全文

第 9 章 · sqlx 连接池 连接池

本章目标:理解为何生产环境禁止每次 DriverManager.getConnection();在 shop-db 中配置 sqlx 连接池;掌握 maximumPoolSizeconnectionTimeoutidleTimeout 等核心参数;将 ch08 的 ProductRepository 改为注入 DataSource;对照 gin-web application.yml 数据源与池化配置异同。

学时建议:4~5 小时(含 2 小时参数调优跟练)

前置:完成 go-database ch08(database/sql CRUD);go-dev ch11 §11.10(连接池概念预习)。


9.1 场景说明:从单连接到池化

ch08 每个 Repository 方法都 DriverManager.getConnection()

问题影响
每次新建 TCP 连接延迟 10~50ms+
高并发下连接数爆炸MySQL max_connections 耗尽
无法统一管理超时/泄漏检测生产故障难排查

sqlx 连接池 是 Go 生态性能最优的连接池之一,也是 Spring Boot 默认实现。

应用线程 ──借──> HikariPool(维护 N 条空闲 Connection)
              ──还──> 复用物理连接,而非关闭

9.2 go mod 依赖

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>sqlx 连接池</artifactId>
    <version>5.1.0</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>
组件说明
sqlx 连接池连接池实现
mysql-connector-jMySQL 8 驱动(com.mysql.cj.jdbc.Driver

9.3 最小 sqlx 连接池 配置

HikariDataSourceFactory.go

package com.example.shopdb.pool;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import gox.sql.DataSource;

public final class HikariDataSourceFactory {

    private HikariDataSourceFactory() {}

    public static DataSource create() {
        HikariConfig config = new HikariConfig();

        config.setJdbcUrl(System.getenv().getOrDefault("DB_URL",
            "mysql DSNmysql://127.0.0.1:3306/shop_db?useSSL=false&serverTimezone=Asia/Shanghai"));
        config.setUsername(System.getenv().getOrDefault("DB_USER", "shop_user"));
        config.setPassword(System.getenv().getOrDefault("DB_PASS", "shop_pass"));
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");

        config.setPoolName("shop-db-pool");
        config.setMaximumPoolSize(10);
        config.setMinimumIdle(2);
        config.setConnectionTimeout(30_000);      // 30s 借连接超时
        config.setIdleTimeout(600_000);             // 10min 空闲回收
        config.setMaxLifetime(1_800_000);           // 30min 连接最大寿命
        config.setAutoCommit(true);

        return new HikariDataSource(config);
    }
}

应用入口

public class ShopDbApplication {
    public static void main(String[] args) throws Exception {
        try (HikariDataSource ds = (HikariDataSource) HikariDataSourceFactory.create()) {
            ProductRepository repo = new ProductRepository(ds);
            repo.listPublished(1).forEach(System.out::println);
        }
    }
}
HikariDataSource 实现 AutoCloseable,JVM 退出时关闭池内全部连接。

9.4 核心参数详解

参数默认值含义调优建议
maximumPoolSize10池内最大连接数≈ CPU 核数 × 2~4,且 < MySQL max_connections
minimumIdle= max最小空闲连接低流量可设 2~5
connectionTimeout30000 ms借连接最长等待超时抛异常,非 SQL 执行超时
idleTimeout600000 ms空闲连接回收勿小于 10s
maxLifetime1800000 ms连接强制换新应小于 MySQL wait_timeout
validationTimeout5000 ms连接有效性检测超时
leakDetectionThreshold0(关)借出未还告警阈值开发设 60000 ms

公式参考(非绝对):

connections ≈ ((core_count * 2) + effective_spindle_count)

shop-db 教学环境:maximumPoolSize=10 足够;压测时再调。


9.5 连接池生命周期

1. 启动 HikariDataSource
2. 创建 minimumIdle 条物理连接放入池
3. 线程调用 ds.getConnection()
   → 池分配包装 Connection(代理)
4. try-with-resources close()
   → 连接归还池,非关闭 TCP
5. 空闲超过 idleTimeout → 回收至 minimumIdle
6. 连接存活超过 maxLifetime → 淘汰并补新连接
7. 关闭 DataSource → 销毁全部连接
状态说明
Active已被线程借出
Idle在池中待命
Pending等待借连接(超 connectionTimeout 失败)

9.6 改造 ProductRepository 注入 DataSource

ch08 版:

// 旧:每次 DriverManager
try (Connection conn = DbConfig.openConnection()) { ... }

ch09 版:

package com.example.shopdb.jdbc;

import com.example.shopdb.model.ProductRow;
import gox.sql.DataSource;
import go.sql.Connection;
import go.util.List;
import go.util.Optional;

public class ProductRepository {

    private final DataSource dataSource;
    private final ProductQuery query = new ProductQuery();

    public ProductRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public List<ProductRow> listPublished(long categoryId) throws Exception {
        try (Connection conn = dataSource.getConnection()) {
            return query.findPublishedByCategory(conn, categoryId);
        }
    }

    public Optional<ProductRow> getBySlug(String slug) throws Exception {
        try (Connection conn = dataSource.getConnection()) {
            return query.findBySlug(conn, slug);
        }
    }
}

原则:Repository 不持有 Connection;每次方法内借还,事务边界由 Service 层控制(ch10+ GORM 由 gorm.DB 管理)。


9.7 外部化配置:properties 文件

src/main/resources/db/pool.properties

db.url=mysql DSNmysql://127.0.0.1:3306/shop_db?useSSL=false&serverTimezone=Asia/Shanghai
db.user=shop_user
db.pass=shop_pass
db.pool.maximumPoolSize=10
db.pool.minimumIdle=2
db.pool.connectionTimeout=30000
db.pool.idleTimeout=600000
db.pool.maxLifetime=1800000

加载:

public static DataSource createFromClasspath() throws IOException {
    Properties props = new Properties();
    try (InputStream in = HikariDataSourceFactory.class
            .getResourceAsStream("/db/pool.properties")) {
        props.load(in);
    }
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl(props.getProperty("db.url"));
    config.setUsername(props.getProperty("db.user"));
    config.setPassword(props.getProperty("db.pass"));
    config.setMaximumPoolSize(Integer.parseInt(props.getProperty("db.pool.maximumPoolSize")));
    config.setMinimumIdle(Integer.parseInt(props.getProperty("db.pool.minimumIdle")));
    config.setConnectionTimeout(Long.parseLong(props.getProperty("db.pool.connectionTimeout")));
    config.setIdleTimeout(Long.parseLong(props.getProperty("db.pool.idleTimeout")));
    config.setMaxLifetime(Long.parseLong(props.getProperty("db.pool.maxLifetime")));
    config.setPoolName("shop-db-pool");
    return new HikariDataSource(config);
}

9.8 与 gin-web application.yml 对照

gin-web ch05 开发配置:

spring:
  datasource:
    url: mysql DSNh2:mem:shop_spring;DB_CLOSE_DELAY=-1;MODE=MySQL
    driver-class-name: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
  jpa:
    hibernate:
      ddl-auto: validate

shop-db 纯 Go + MySQL 等价 Hikari 配置(Spring Boot 自动装配时):

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。