【SQLAlchemy】第二篇——连接失效及连接池

news2024/11/18 1:28:59

一、背景

为了节约资源,MySQL会对建立的连接进行监控,当某些连接处于不活跃状态的时间超过一个阈值时,则关闭它们。

用户可以执行show variables like '%wait_timeout%';来查看这个阈值:

请添加图片描述

可以看到,在默认的情况下,这个阈值是28800秒,即,如果一个连接处于不活跃的时间超过8小时,则该连接不再可用。

下面给出一个具体的例子。

1、为了能够快速验证,首先使用set global wait_timeout=10;语句将该阈值设置为10。

设置成功后需要通过show global variables like '%wait_timeout%';进行查看。为什么要加global?可以参考这里。

2、执行以下验证代码:

from sqlalchemy import create_engine, text
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/platform')
sql = "select 1+1;"
with engine.connect() as conn:
    res = conn.execute(text(sql))
    print(res.fetchone()[0])

打印结果2

3、等待超过10秒钟后,再次执行上述代码中的with:部分,则会得到如下错误:

sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')

即无法连接到MySQL服务器。

二、问题

设想这样一个场景:通过flask启动了一个REST服务,该服务需要访问数据库,且每天被定时请求一次(除此之外无请求)。

按照上一节的讨论,由于两次请求间隔(24小时)超过了关闭阈值(8小时),因此在下一次发送请求时,会报出Lost connection的错误。

三、解决方案

一个可选的解决方案是,增加wait_timeout的值,使之超过24小时。但这样很可能导致数据库中存在大量的处于sleep状态的进程,从而造成资源的浪费。这里不考虑此种方案。

既然是连接失效,那么一种比较直观的解决方案就是在每次使用连接进行数据库操作前,先检验一下连接是否有效。有效就直接使用;无效则重新连接

SQLAlchemy提供了基于上述思路的解决方案——指定pool_pre_ping参数:

engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/platform', pool_pre_ping=True)

这样定义engine之后,再执行上面的验证例子可以发现,即使两次执行with:的间隔超过了阈值,仍可以执行成功。

四、更深入的分析

4.1 Engine与连接池

本系列的第一篇中说“可以将Engine对象视为连接池”,但严格来讲这是不正确的。要正确理解它们之间的关系,需要借助下面这张结构图:

请添加图片描述

最右侧是数据库,SQLAlchemy通过第三方的DBAPI与之进行连接——在上面的例子中,这个DBPAI是PyMySQL。而上述Engine对象则是通过PoolDialect来与DBPAI进行交互。

先说Dialect,这个单词的字面意思是“方言”,在这里可以引申为不同的数据库类型。在上面定义engine的url中的mysql实际上就告诉SQLAlchemy要初始化一个支持连接MySQLDialect类。

当使用create_engine函数创建Engine对象时,默认使用QueuePool来创建连接池,用户可以指定poolclass参数来选择不同的Pool。当调用Engineconnect()方法时,就会从连接池中获取一个连接对象来执行操作。

4.2 pool_pre_ping的限制

仔细分析不难看出,第三部分提供的方案是有弊端的。在使用从连接池获取的连接进行实际工作前,都需要向数据库服务器发送ping命令,这无疑会增加开销。

所谓的“发送ping命令”是一个概括的说法,有可能是通过连接向服务器发送了select 1;等简单的命令。

另外,如果服务器出现了性能瓶颈,可能导致ping命令迟迟得不到有效的相应,从而影响程序性能。

因为上述原因,pool_pre_ping方法被称为是“悲观的”。

4.3 乐观方法

上述悲观方法是被动式的——要等到连接不可用了之后,才能通过ping命令检测到。而乐观方法则是主动式的:通过在调用create_engine时设置pool_recycle参数来指定连接持续时间。这个参数的作用是,在达到pool_recycle的时间限制后,连接池将所有的连接回收,并重新进行连接。这样就保证了连接的有效性。

与悲观方法相比,乐观方法减轻了服务器的负担。

4.4 连接池

直观地查看一下连接池的作用:

# 代码由chatGPT生成
from sqlalchemy import create_engine, text
import concurrent.futures
import threading

# 创建连接池引擎
# 这里限制了池中连接的数量为3,且不允许自动增加连接的数量
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/test', pool_size=3, max_overflow=0)


# 定义并发函数
# 为了能从数据库服务器查看连接的执行情况,执行了一个休眠命令
def run_query(query_num):
    print('线程:', threading.current_thread().native_id, '正在执行...')
    with engine.connect() as conn:
        ret = conn.execute(text(f'select sleep({query_num})'))
    print('线程:', threading.current_thread().native_id, '执行完成')
    return ret.one()[0]


# 使用多线程并发执行查询
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    # 线程池中共有10个线程
    futures = []
    for i in range(10):
        futures.append(executor.submit(run_query, 5))
    for future in concurrent.futures.as_completed(futures):
        print(future.result())

执行上述代码,首先在控制台上打印出类似如下的内容:

线程: 517317 正在执行...
线程: 517318 正在执行...
线程: 517319 正在执行...
线程: 517321 正在执行...
线程: 517322 正在执行...
线程: 517320 正在执行...
线程: 517323 正在执行...
线程: 517325 正在执行...
线程: 517326 正在执行...
线程: 517324 正在执行...

这说明,10个线程已经开始执行。但由于连接池中只有3个连接,此时通过show processlist可以看到有三个连接在执行操作:

请添加图片描述

结合控制台打印的输出,当有线程执行完成时,数据库中对应连接的Time字段又从0开始计时,这说明改连接被复用了。

当所有的线程执行完成后,上述三个连接消失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/389087.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Multi-modal Graph Contrastive Learning for Micro-video Recommendation

模型总览如下: 解决问题:同种重要性对待每种模态,可能使得得到的特征表示次优,例如过度强调学习到的表示中的特定模态。以MMGCN为例,下图为MMGCN模型总览。 如上图所示MMGCN在每种模态上构建用户-物品二部图&#xff0…

【云原生】Gateway网关选型

网关一般分为流量网关和业务网关,流量网关负责接入所有的流量,并分发给不同的子系统,那在具体的业务接入之前,还有一层业务网关。流量网关提供全局性的、与后端业务应用无关的策略,例如 HTTPS证书卸载、Web防火墙、全局…

[vue]vue3.x 组合式API不同写法

[vue]vue3.x 组合式API不同写法改进后组合API实际实际使用中的疑问组件名称问题两种写法的优缺点对比优点缺点组合式API,采用了更加灵活的方式,官网推荐的语法糖,但仅限于比较简单的单文件,作为尝试 改进后组合API实际实际使用中的疑问 改进…

4-2 Linux进程和内存概念

文章目录前言进程状态进程优先级内存模型进程内存关系前言 进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝。 进程状态…

36_2 On Chip Bus —— AXI总线介绍

目录 1.AXI总线介绍(读2写3) 1.1流量控制 1.2 AXI signals 信号线 1.3重点信号线的介绍 1.4原子操作——让读改写一套操作 永远是一个master对一个slave 1.5AXI BURST Boundary——一个burst不能跨4k boundary,master要保证 1.6读/写通…

k8s中的PV和PVS

前言:容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)…

Python 算法交易实验51 Step2 Signals 信号生成

说明 不可不读书 先从经典的一些超简单信号开始 使用移动平均指标SMA(算术) 给出了信号的产生方法,还有一些测算结果,反正看起来都是盈利的 首先使用离线方法实验一组结果,然后就使用ADBS来进行类似的处理。 内容 1 原理分析…

【python中的列表和元组】

文章目录前言一、列表及其使用1.列表的特点2. 列表的使用方法二、元组及其特点1.元组的类型是tuple1.元组的查找操作2. 计算元组某个元素出现的次数3.统计元组内元素的个数总结前言 本文着重介绍python中的列表和元组以及列表和元组之间的区别 一、列表及其使用 1.列表的特点…

JavaSE学习进阶day2_02 抽象类和接口

第四章 抽象类 4.1 概述 4.1.1 抽象类引入 先看一张图: 这张图时之前学习继承时用的,但是现在有一个疑问,吃饭这个行为猫和狗都有,但是它们吃的东西却又不同,这个时候我们不能确定父类吃饭这个方法到底该写什么&…

数据库分库分表策略

一、MySQL扩展具体的实现方式 随着业务规模的不断扩大,需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。 关于数据库的扩展主要包括:业务拆分、主从复制,数据库分库与分表。这篇文章主要讲述数据库分库…

03-SQLPlus的常用命令和使用

本章内容讲解SQLPlus的常用命令使用方法,参数的设置,帮助的使用,详细讲解如下: 登录SQL*Plus DOS方式登录SQL*Plus C:\>sqlplus 提示输入用户名、密码 C:\>sqlplus scott/tiger 连到默认数据库,注册表或环境变量中设 …

Blender——植物生长动画制作

效果图前言参考链接:https://www.bilibili.com/video/BV1aY411G7bk/?spm_id_from333.788.recommend_more_video.10&vd_source5212838c127b01db69dcc8b2d27ca517建议Blender的版本在3.0.0或以上。制作完成的植物生长动画blender文件下载:https://dow…

SpringCloud之ElasticSearch笔记

ElasticSearch 初识ElasticSearch ElasticSearch是什么 ElasticSearch一个基于Lucene的底层的开源的分布式搜索引擎,可用来实现搜索,日志统计,分析,系统监控 正向索引和倒排索引 正向索引:逐条扫描(my…

Databend v1.0 Release 正式发布

尊敬的 Databenders,在 Databend Labs 成立两周年之际,我们非常高兴地宣布 Databend v1.0 正式发布。 Databend 社区一直在致力于解决大数据分析的成本和复杂度问题,并正在被顶级场景和顶级需求所推动。 根据可统计信息,每天约 7…

2023年“中银杯”安徽省职业院校技能大赛网络安全A模块全过程解析

A模块基础设施设置/安全加固(200分) 一、项目和任务描述: 假定你是某企业的网络安全工程师,对于企业的服务器系统,根据任务要求确保各服务正常运行,并通过综合运用登录和密码策略、流量完整性保护策略、事件监控策略、防火墙策略等多种安全策略来提升服务器系统的网络安全…

K8S 实用工具之三 - 图形化 UI Lens

开篇 📜 引言: 磨刀不误砍柴工工欲善其事必先利其器 第一篇:《K8S 实用工具之一 - 如何合并多个 kubeconfig?》第二篇:《K8S 实用工具之二 - 终端 UI K9S》 像我这种,kubectl 用的不是非常溜,经…

指针面试笔试题练习

前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨星光…

webGL编程指南实战教程

学习路线: 如果你是在校大学生,有足够的时间去学习:前端>数学(几何线性代数)>图形学>webgl>shader >threejs>three.js源码如果你是工作中使用,需要快速出产成品:前端>thr…

【博学谷学习记录】超强总结,用心分享 | 架构师 JDK源码学习总结

文章目录HashMap类1.定义2.哈希表3.JDK1.8前HashMap的数据结构4.JDK1.8后HashMap的数据结构5.类构造器6.字段属性①Node<K,V>[] table②size③loadFactor④threshold7.构造函数①默认无参构造函数②指定初始容量的构造函数8.确定哈希桶数组索引位置9.添加元素10.扩容机制…

操作系统重难点笔记

1.信号量机制&#xff0c;读者/写者问题 读者/写者问题分为两种情况&#xff1a; 1.读者和写者互斥&#xff0c;并且不同的读者和写者之间都互斥,一共三个互斥 下面给出伪代码 int m1; int mr1; int mw1; int count0; writer() {while(1){P(mw);........V(mw);} } reader() {…