🔹 连接管理 使用连接池(如 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():通知所有等待的线程。
其实“池化”本质上就是“有限资源复用管理”的通用设计模式,连接池、线程池、对象池都属于这类模式。
2634

被折叠的 条评论
为什么被折叠?



