Flask数据库连接池

Flask数据库连接池

一、问题引入

  • 安装模块

    • pip install pymysql
      
  • 简单示例

    • import pymysql
      
      # 连接数据库
      conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
      # 创建游标对象,返回字典类型
      cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
      # 使用参数化查询执行SQL语句,传入参数使用字典形式
      cursor.execute("select * from users")
      # 获取查询结果中的下一行,返回字典形式
      obj = cursor.fetchone()
      # 提交事务
      conn.commit()
      # 关闭游标
      cursor.close()
      # 关闭数据库连接
      conn.close()
      
      # 打印查询结果
      print(obj)
      
      
  • 在 Flask 应用中,如果直接在全局范围内创建数据库连接(conn)和游标(cursor),会导致以下问题:

    • 当应用运行在多进程模式下时,多个进程会同时操作同一个数据库连接,可能会导致数据库操作错乱。
    • 每次请求都应该使用独立的数据库连接,以保证数据库操作的隔离性和安全性。

二、优化方案

为了解决上述问题,可以采取以下优化措施:

  1. 在每个请求的视图函数中独立创建和关闭数据库连接。
  2. 使用数据库连接池来管理数据库连接,提高资源利用率和应用性能。

1. 独立创建和关闭数据库连接

在每个视图函数中,创建数据库连接和游标,执行完数据库操作后关闭它们:

@app.route('/', methods=['GET', 'POST'])
def index():
    # 创建数据库连接和游标
    conn = pymysql.connect(...)  # 省略了连接参数
    cursor = conn.cursor(cursor=DictCursor)
    
    try:
        cursor.execute("SELECT * FROM test WHERE ID < 10")
        res = cursor.fetchall()
        print(res)
    finally:
        # 确保游标和连接被关闭
        cursor.close()
        conn.close()
    return 'index'

2. 使用数据库连接池

使用 dbutils 库的 PooledDB 创建一个数据库连接池,并通过单例模式管理它:

安装模块:pip install dbutils

设置数据库连接池(settings.py):

# pip install dbutils
import pymysql
from dbutils.pooled_db import PooledDB


class Config(object):
 DEBUG = True
 # 其他配置..

 # 创建数据库连接池
 PYMYSQL_POOL = PooledDB(
     creator=pymysql,  # 使用链接数据库的模块
     maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
     mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
     maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
     maxshared=3,
     # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
     blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
     maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
     setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
     ping=0,
     # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
     host='127.0.0.1',
     port=3306,
     user='root',
     password='123456',
     database='test',
     charset='utf8',
     cursorclass=pymysql.cursors.DictCursor
 )

使用连接池:

from flask import Flask
from settings import Config

app = Flask(__name__)
app.config.from_object(Config)


@app.route('/')
def index():
    conn = Config.PYMYSQL_POOL.connection()
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM user")
    users = cursor.fetchall()
    print(users)
    return "Hello World!"

三、测试连接池

1.使用数据库连接池

优点

  • 减少了数据库连接的开销,提高了性能。
  • 限制了同时打开的连接数,有助于防止数据库过载。

示例

@app.route('/pool')
def pool():
    conn = Config.PYMYSQL_POOL.connection()  # 从池中获取连接
    # ... 执行数据库操作 ...
    conn.close()  # 返回连接到池中,而不是关闭它
    return jsonify(res)

2.不使用数据库连接池

缺点

  • 每次请求都创建和关闭连接,增加了数据库的开销。
  • 如果并发请求很多,可能导致数据库连接数过多,甚至引发错误。

示例

@app.route('/no_pool')
def no_pool():
    conn = pymysql.connect(...)  # 手动创建连接
    # ... 执行数据库操作 ...
    conn.close()  # 关闭连接
    return jsonify(res)

3.测试结果

  • 测试脚本

    • import requests
      from threading import Thread
      
      
      # 没有连接池
      def task():
          # res = requests.get('http://127.0.0.1:5000/no_pool') # 没有池
          res = requests.get('http://127.0.0.1:5000/pool')  # 有池
          print(res.json())
      
      
      if __name__ == '__main__':
          l = []
          for i in range(100):
              t = Thread(target=task)
              t.start()
              l.append(t)
      
          for i in l:
              i.join()
      
  • 查看数据库连接数

SHOW STATUS LIKE '%Threads%';
  • 测试结果
    • 使用连接池:连接数明显较少,因为连接被重用。
    • 不使用连接池:连接数很大,因为每个线程都创建了一个新的连接。
  • 使用连接池的测试明显比不使用连接池的测试慢?
    • 池大小限制:如果池中的连接数不足以满足并发请求的数量,线程需要等待可用连接,这会增加响应时间。
    • 连接创建时间:如果连接池中的连接创建时间较长,或者池中的连接被频繁创建和销毁,也会导致性能下降。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值