什么是连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
为什么要使用连接池
一次数据库的步骤
- TCP建立连接的三次握手
- MySQL认证的三次握手
- 真正的SQL执行
- MySQL的关闭
- TCP的四次握手关闭
利用连接池后
连接池优点
- 较少了网络开销
- 系统的性能会有一个实质的提升
- 没了麻烦的TIME_WAIT状态
连接池实战
预备1:模拟并发处理
由于只有并发处理才能体现连接池的价值。所以要试验连接池前我们先搞一个并发函数。
要求如下:
- 可以设置并发量
- 可以设置总执行次数
- 可以打印每次执行的耗时和总耗时
const sleep = delay => new Promise(resolve => setTimeout(resolve, delay)) const asyncFun = async (fun, curMax = 4, sum = 200) => { let num = 0 let curNum = 0 console.time('总耗时'); console.log('beginTime:' + new Date().toLocaleString()) const result = [] while (num !== sum) { if (curNum <= curMax) { result.push(new Promise(async resolve => { console.log(`Process Run 并发数:${curNum} 完成:${num}/${sum} `) res = await fun() curNum-- resolve(res) })) num++ curNum++ } else { await sleep(10) } } console.log('endTime:' + new Date().toLocaleString()) console.timeEnd('总耗时'); } module.exports = { asyncFun } // 测试 const test = async () => { const delay = (Math.random() * 1000).toFixed() await sleep(delay) } setTimeout(() => asyncFun(test, 4, 20))
预备2:mysql查看连接数
mysqladmin -uroot -pexample processlist
未使用连接池
(async () => { // get the client const mysql = require('mysql2/promise'); // 连接配置 const cfg = { host: "localhost", user: "root", password: "example", // 修改为你的密码 database: "shop", // 请确保数据库存在 connectionLimit : 5, } // 非连接池 const query = async () => { const connection = await mysql.createConnection(cfg) const [rows, fields] = await connection.execute(`SELECT * FROM users`) // console.log('select:', rows) connection.destroy() } const { asyncFun } = require('./async') await asyncFun(query, 20, 1000) })()
执行耗时
数据库的连接数
使用连接池
下面我们改用连接池方式
// 设置连接池 const pool = await mysql.createPool(cfg) // 连接池 const query = async () => { const connection = await pool.getConnection() const [rows, fields] = await connection.execute(`SELECT * FROM users`) // console.log('select:', rows) connection.release() }
执行耗时
数据库的连接数
数据对比与总结
非连接池 | 连接池 | |
总耗时 | 7.043 | 1.459s |
连接数 | 20(等于并发数) | 5(连接池连接数) |
在处理中只使用了五个连接有效的节省了系统资源,并且提升了性能总耗时只有原来的大约五分之一。
数据库中间件中的连接池设置
(async () => { const Sequelize = require("sequelize"); // 建立连接 const sequelize = new Sequelize("kaikeba", "root", "example", { host: "localhost", dialect: "mysql", // operatorsAliases: false, pool: { max: 10, min: 0, idle: 30000 } }); // 定义模型 const Fruit = sequelize.define("Fruit", { name: { type: Sequelize.STRING(20), allowNull: false }, price: { type: Sequelize.FLOAT, allowNull: false }, stock: { type: Sequelize.INTEGER, defaultValue: 0 } }); // 同步数据库,force: true则会删除已存在表 let ret = await Fruit.sync({ force: true }) console.log('sync', ret) ret = await Fruit.create({ name: "香蕉", price: 3.5 }) // console.log('create', ret) const find = async () => { Fruit.findAll() // console.log('findAll', JSON.stringify(ret, '', '\t')) } // await find() const { asyncFun } = require('./async') asyncFun(find,20,100) })()