数据库——连接池管理+减少事务持有时间

🔹 连接管理 使用连接池(如 MySQL 的连接池)减少频繁连接/断开的开销 减少事务持有时间,避免锁表

2. 减少事务持有时间,避免锁表
背景

事务中的操作(尤其写操作)通常会对数据加锁,防止其他操作读写冲突。如果事务持续时间长,锁会一直存在,导致其他操作等待,甚至“锁表”,影响并发。

减少事务持有时间

就是让事务尽量短,快速执行完提交或回滚,尽早释放锁,减少对其他操作的影响。

举个例子

假设有一个库存管理系统:

糟糕的做法:
一个事务开始后,先从数据库读取库存,然后在程序中做复杂的计算(耗时几秒),再更新库存,最后提交事务。这个事务期间,库存表的相关记录被锁住,其他请求必须等待。

优化做法:
事务只做必要的数据库操作:

BEGIN;
UPDATE inventory SET quantity = quantity - 1 WHERE product_id = 123 AND quantity > 0;
COMMIT;


其他计算逻辑放到事务外完成,或者提前准备好。这样事务很快完成,锁释放,其他请求不会长时间等待。
1. 连接管理 — 使用连接池
背景

数据库连接的建立和断开是非常耗时的操作。假如你的应用每来一次请求都新建一个数据库连接,处理完就断开,频繁建立/断开连接会极大影响性能。

连接池的作用

连接池预先创建一定数量的数据库连接,存放在池子里,应用程序用时直接从池子里拿连接,用完放回池子,下次复用。避免了频繁创建和关闭连接的开销。

举个例子

假设你有一个网站,每秒有 100 个用户请求,每个请求都要访问数据库。

没用连接池:
每次请求都创建一个新连接,处理完关闭。每秒要创建并关闭 100 个连接。连接操作耗时假设 50ms,那么单是连接的开销就是 100 × 50ms = 5秒,明显不合理。

用连接池:
连接池维护 10 个连接,用户请求时直接拿连接,处理完放回连接池。连接创建仅发生在程序启动时和连接断开重连时,极大减少连接开销。
预先创建一批连接放到池子里

需要连接时从池里拿

用完归还连接

池中连接复用,避免频繁创建销毁

简单示例代码(伪代码+简化示范)
#include <iostream>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <mysql_driver.h>
#include <mysql_connection.h>

using namespace sql::mysql;
using namespace sql;

class MySQLConnectionPool {
public:
    MySQLConnectionPool(const std::string& url, const std::string& user, const std::string& password, int poolSize) 
        : driver_(sql::mysql::get_mysql_driver_instance()), pool_size_(poolSize) {
        for (int i = 0; i < pool_size_; ++i) {
            std::unique_ptr<Connection> conn(driver_->connect(url, user, password));
            connections_.push(std::move(conn));
        }
    }

    std::unique_ptr<Connection> getConnection() {
        std::unique_lock<std::mutex> lock(mutex_);
        // 等待直到有空闲连接
        cond_.wait(lock, [this]() { return !connections_.empty(); });

        auto conn = std::move(connections_.front());
        connections_.pop();
        return conn;
    }

    void returnConnection(std::unique_ptr<Connection> conn) {
        std::lock_guard<std::mutex> lock(mutex_);
        connections_.push(std::move(conn));
        cond_.notify_one();
    }

private:
    sql::mysql::MySQL_Driver* driver_;
    std::queue<std::unique_ptr<Connection>> connections_;
    int pool_size_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

// 使用示范
int main() {
    MySQLConnectionPool pool("tcp://127.0.0.1:3306", "root", "password", 5);

    // 从连接池拿连接
    auto conn = pool.getConnection();

    // 使用连接查询
    std::unique_ptr<Statement> stmt(conn->createStatement());
    std::unique_ptr<ResultSet> res(stmt->executeQuery("SELECT * FROM your_table LIMIT 5"));

    while (res->next()) {
        std::cout << "Column1: " << res->getString(1) << std::endl;
    }

    // 归还连接给连接池
    pool.returnConnection(std::move(conn));

    return 0;
}

说明

连接池里维护了一批连接(poolSize=5)。

getConnection() 拿连接,如果没有空闲连接会等待。

连接使用完后通过 returnConnection() 放回连接池。

用 unique_ptr 管理连接生命周期,避免内存泄漏。

这样就避免了每次查询都新建和关闭连接的开销。
具体解释:

std::condition_variable 是一个线程同步原语,用来阻塞一个线程,直到被另一个线程通知。

notify_one() 的作用是唤醒一个正在等待该条件变量的线程。

在你那个代码里的上下文:
std::condition_variable cond_;
...
cond_.notify_one();


这里 cond_ 是一个 std::condition_variable 对象。

调用 cond_.notify_one() 会通知一个因为调用了 cond_.wait() 而阻塞的线程,让它从阻塞状态中醒过来,重新竞争互斥锁,继续执行。

简单说明:

wait():线程进入等待状态,阻塞直到被通知。

notify_one():通知一个等待的线程可以继续执行。

notify_all():通知所有等待的线程。

其实“池化”本质上就是“有限资源复用管理”的通用设计模式,连接池、线程池、对象池都属于这类模式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值