Ormer
Home
快速开始
GitHub
  • 简体中文
  • English
Home
快速开始
GitHub
  • 简体中文
  • English
  • Ormer 简介
  • 快速开始
  • 模型定义
  • 数据库连接
  • 数据操作
  • 查询构建器
  • 高级查询
  • 事务管理
  • 连接池

连接池

连接池是管理数据库连接的重要机制,可以显著提高应用性能和资源利用率。

什么是连接池

连接池维护一组预先创建的数据库连接,应用可以复用这些连接,避免频繁创建和销毁连接的开销。

优势

  • 性能提升 - 避免每次操作都创建新连接
  • 资源控制 - 限制最大连接数,防止数据库过载
  • 连接复用 - 自动管理连接的生命周期
  • 故障恢复 - 自动检测和替换失效连接

创建连接池

基本用法

use ormer::{Database, DbType, ConnectionPool};

let pool = Database::create_pool(DbType::PostgreSQL, "postgresql://user:pass@localhost/dbname")
    .max_size(10)  // 最大连接数
    .build()
    .await?;

配置选项

let pool = Database::create_pool(DbType::PostgreSQL, connection_string)
    .max_size(20)        // 最大连接数 (默认: 10)
    .min_size(5)         // 最小空闲连接数 (可选)
    .idle_timeout(300)   // 空闲超时时间 (秒) (可选)
    .build()
    .await?;

使用连接池

获取连接

// 从连接池获取连接
let conn = pool.get().await?;

// 使用连接
let users: Vec<User> = conn
    .select::<User>()
    .collect()
    .await?;

// 连接会自动返回连接池

自动连接管理

连接池会自动管理连接:

async fn handle_request(pool: &ConnectionPool) -> Result<(), Box<dyn std::error::Error>> {
    // 获取连接
    let conn = pool.get().await?;
    
    // 执行操作
    conn.insert(&user).await?;
    
    // conn 超出作用域后自动返回连接池
    Ok(())
}

完整示例

Web 应用示例

use ormer::{Database, DbType, ConnectionPool, Model};
use std::sync::Arc;
use tokio::sync::Mutex;

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    name: String,
    email: String,
}

struct AppState {
    pool: ConnectionPool,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建连接池
    let pool = Database::create_pool(
        DbType::PostgreSQL,
        "postgresql://user:pass@localhost/mydb"
    )
    .max_size(20)
    .build()
    .await?;
    
    let state = Arc::new(AppState { pool });
    
    // 模拟处理多个请求
    let mut handles = vec![];
    
    for i in 0..10 {
        let state = state.clone();
        let handle = tokio::spawn(async move {
            // 从连接池获取连接
            let conn = state.pool.get().await.unwrap();
            
            // 执行数据库操作
            let users: Vec<User> = conn
                .select::<User>()
                .range(0..10)
                .collect()
                .await
                .unwrap();
            
            println!("Request {}: {} users", i, users.len());
        });
        
        handles.push(handle);
    }
    
    // 等待所有请求完成
    for handle in handles {
        handle.await.unwrap();
    }
    
    Ok(())
}

连接池配置示例

use ormer::{Database, DbType};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 开发环境: 少量连接
    let dev_pool = Database::create_pool(
        DbType::Turso,
        "file:dev.db"
    )
    .max_size(5)
    .build()
    .await?;
    
    // 生产环境: 更多连接
    let prod_pool = Database::create_pool(
        DbType::PostgreSQL,
        "postgresql://user:pass@localhost/prod_db"
    )
    .max_size(50)
    .min_size(10)
    .idle_timeout(600)  // 10 分钟
    .build()
    .await?;
    
    Ok(())
}

连接池最佳实践

1. 合理设置连接数

// ✅ 推荐: 根据服务器配置设置
let pool = Database::create_pool(DbType::PostgreSQL, &db_url)
    .max_size(num_cpus::get() * 4)  // CPU 核心数的 4 倍
    .build()
    .await?;

// ❌ 避免: 连接数过大或过小
.max_size(1000)  // 太大,浪费资源
.max_size(1)     // 太小,性能差

2. 使用连接池而非单个连接

// ✅ 推荐: 使用连接池
let pool = Database::create_pool(DbType::PostgreSQL, &db_url)
    .max_size(20)
    .build()
    .await?;

async fn handle_request(pool: &ConnectionPool) {
    let conn = pool.get().await?;
    // 使用 conn...
}

// ❌ 避免: 每次创建新连接
async fn handle_request_bad(db_url: &str) {
    let db = Database::connect(DbType::PostgreSQL, db_url).await?;
    // 使用 db...
} // 连接被丢弃

3. 及时释放连接

// ✅ 推荐: 连接在使用后自动返回池
{
    let conn = pool.get().await?;
    conn.insert(&user).await?;
} // conn 在这里被释放

// ❌ 避免: 长时间持有连接
let conn = pool.get().await?;
tokio::time::sleep(Duration::from_secs(60)).await;  // 不好!
conn.insert(&user).await?;

4. 错误处理

async fn safe_query(pool: &ConnectionPool) -> Result<Vec<User>, Box<dyn std::error::Error>> {
    let conn = pool.get().await?;
    
    let users = conn
        .select::<User>()
        .collect::<Vec<_>>()
        .await?;
    
    Ok(users)
}

监控连接池

连接池状态

// 某些连接池实现提供状态监控
println!("Active connections: {}", pool.active_connections());
println!("Idle connections: {}", pool.idle_connections());
println!("Total connections: {}", pool.total_connections());

性能指标

监控以下指标:

  • 等待时间 - 获取连接的等待时间
  • 活跃连接数 - 正在使用的连接数
  • 空闲连接数 - 可用的连接数
  • 连接错误率 - 连接失败的次数

不同数据库的连接池配置

Turso/SQLite

let pool = Database::create_pool(DbType::Turso, "file:test.db")
    .max_size(10)  // SQLite 通常不需要太多连接
    .build()
    .await?;

PostgreSQL

let pool = Database::create_pool(
    DbType::PostgreSQL,
    "postgresql://user:pass@localhost/dbname"
)
.max_size(20)  // PostgreSQL 支持较多并发连接
.min_size(5)
.build()
.await?;

MySQL

let pool = Database::create_pool(
    DbType::MySQL,
    "mysql://user:pass@localhost/dbname"
)
.max_size(20)
.min_size(5)
.build()
.await?;

常见问题

1. 连接池耗尽

当所有连接都在使用时,新的请求会等待:

// 连接池已满,这里会阻塞直到有连接可用
let conn = pool.get().await?;

解决方法:

  • 增加 max_size
  • 优化查询,减少连接占用时间
  • 使用超时机制
// 带超时的获取连接
let conn = tokio::time::timeout(
    Duration::from_secs(5),
    pool.get()
).await??;

2. 连接泄漏

忘记释放连接会导致连接泄漏:

// ❌ 错误: 连接未释放
let conn = pool.get().await?;
// 函数返回但没有释放 conn

// ✅ 正确: 使用作用域
{
    let conn = pool.get().await?;
    // 使用 conn
} // conn 自动释放

3. 连接失效

数据库重启或网络问题会导致连接失效:

// 连接池通常会自动处理
let conn = pool.get().await?;

// 如果连接失效,重新获取
match conn.select::<User>().collect().await {
    Ok(users) => println!("Got {} users", users.len()),
    Err(_) => {
        // 连接池会自动替换失效连接
        let conn = pool.get().await?;
        let users: Vec<User> = conn.select::<User>().collect().await?;
    }
}

性能调优

1. 根据负载调整连接数

// 低负载应用
.max_size(5)

// 中等负载
.max_size(20)

// 高负载应用
.max_size(50)

2. 设置合理的超时

// 连接获取超时
.max_wait_time(5)  // 5 秒

// 空闲超时
.idle_timeout(300)  // 5 分钟

3. 预创建连接

// 启动时创建最小连接数
let pool = Database::create_pool(DbType::PostgreSQL, &db_url)
    .min_size(10)  // 预创建 10 个连接
    .build()
    .await?;
Prev
事务管理