Flask 的 数据库连接 与 DBUtils 数据库连接池

Flask 的 数据库连接 与 DBUtils 数据库连接池

1本地线程:thread_local 2 3 为每个线程创建存储数据的空间,用于线程之间的数据隔离 4 否则多个线程同时访问,会使得数据混乱

<br> <br>

1 Flask 连接数据库 的方法

1 pymysql 2 3 依赖 SQLArchemy
<br>

数据库连接的方案

11 每次请求反复的创建数据库连接 (可以并发请求 -- 但是每次都会创建连接) 2 # 连接数太多 3 42 将连接放在全局变量 单线程(没有问题) pymysql 只能支持单线程 5 # 不能支持并发 6 7 83 import threading 9 LOCK = threading.RLock() 10 with LOCK: 11 connect --- 12 ... 13 # 这样控制每次只能有一个线程连接 (不能并发操作) 14 # 不加锁 ,多线程状况下 会报错 15 16 174 基于 DBUtils 实现 数据库连接池 18 19 -- 为每一个线程创建一个连接,当连接关闭的时候,不是真正的关闭; 20 当本线程再次使用的时候,还是使用最开始的连接, 21 只有当线程终止的时候,连接才会关闭 22 23 -- 创建一个连接池(列表),为所有的线程 提供连接,使用完毕 再放回连接池 24 所有的连接都可以被重复使用,共享 25 26 -- 基于实现本地线程: 线程间的数据隔离
<br> <br>

2 为什么要使用数据库连接池

如果没有连接池,使用pymysql来连接数据库时,单线程应用完全没有问题,但如果涉及到多线程应用那么就需要加锁,一旦加锁那么连接势必就会排队等待,当请求比较多时,性能就会降低了

    实现并发,避免无限制的连接
<br> <br>

3 使用DBUtils 数据库连接池

    DBUtils是Python的一个用于实现数据库连接池的模块
<br>

模式一:为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接自动关闭

1基于本地线程 每个线程创建一个本地线程 2 3POOL = PersistentDB( 4 creator=pymysql, # 使用链接数据库的模块 5 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 6 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] 7 ping=0, 8 # 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 9 closeable=False, 10 # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接) 11 threadlocal=None, # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置 12 host='127.0.0.1', 13 port=3306, 14 user='root', 15 password='123', 16 database='pooldb', 17 charset='utf8' 18) 19 20def func(): 21 conn = POOL.connection(shareable=False) 22 cursor = conn.cursor() 23 cursor.execute('select * from tb1') 24 result = cursor.fetchall() 25 cursor.close() 26 conn.close() # 结束本次连接,供本线程再次使用 27 28func()
<br>

模式二:创建一批连接到连接池,供所有线程共享使用

1先 创建本地连接,让所有线程公用 2 3PS:由于pymysql、MySQLdb等threadsafety值为1,所以该模式连接池中的线程会被所有线程共享。 4所以 最大共享数 无用的。

这种模式是最常使用的

1db.py: 2 3 import time 4 import pymysql 5 import threading 6 from DBUtils.PooledDB import PooledDB, SharedDBConnection 7 POOL = PooledDB( 8 creator=pymysql, # 使用链接数据库的模块 9 maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 10 mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 11 maxcached=5, # 链接池中最多闲置的链接,0和None不限制 12 maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 13 blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 14 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 15 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] 16 ping=0, 17 # 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 18 host='127.0.0.1', 19 port=3306, 20 user='root', 21 password='123', 22 database='pooldb', 23 charset='utf8' 24 ) 25 26 27使用的时候: 28 29 from db import POOL 30 31 def func(): 32 # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常 33 # 否则 34 # 则优先去初始化时创建的链接中获取链接 SteadyDBConnection。 35 # 然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。 36 # 如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。 37 # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。 38 39 conn = POOL.connection() 40 41 # print(th, '链接被拿走了', conn1._con) 42 # print(th, '池子里目前有', pool._idle_cache, '\r\n') 43 44 cursor = conn.cursor() 45 cursor.execute('select * from tb1') 46 result = cursor.fetchall() 47 conn.close() # 结束本次连接,把连接放回连接池 48 49 func()
<br>

小结

11 每次操作都要连接 --- 不允许 2 32 公用一个连接,多线程会出问题, 加锁-->> 变成了串行 4 53 DBUtils 数据库连接池: 6 (1) 基于treading.local 实现为每一个线程 创建一个连接,当前线程可以反复使用本线程的连接,线程终止的时候连接关闭 7 8 # treading.local 为每一个线程创建一份独立的值,相当于一个字典(每个线程的唯一标识为 键) 9 10 (2) 设置最大连接数 11 默认启动时,连接池中创建的连接 12 13 # 1个连接可以为3个线程服务(可能中途返还)
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )