看代码,
from flask import Flaskfrom db import POOLimport pymysqlapp = Flask(__name__)app.secret_key ='sdfsdfsdf'@app.route('/index')def index(): # 第一步:缺点:每次请求反复创建数据库连接,连接数太多。 # conn = pymysql.connect() # cursor = conn.cursor() # cursor.execute('select * from tb where id > %s',[5,]) # result = cursor.fetchall() # cursor.close() # conn.close() # print(result)
对于这种方式,每来一个用户请求,都要去创建一个链接。对于数据库来说,过分了。可并发,但是连接数太多。
就算你改成在全局创建,只用一个链接,但是会变成串行。
如果是多线程的话,这样的方式是不是会报错哦?pymysql它同一时间只能处理一个线程。
那来,我们这样玩,还是在将链接操作放在全局。
# 第二步:缺点,不能支持并发 # pymysql.threadsafety # with LOCK: # cursor = CONN.cursor() # cursor.execute('select * from tb where id > %s', [5, ]) # result = cursor.fetchall() # cursor.close() # # print(result)
加把锁。这样支持多线程了吧?
可是。。。 它支持并发吗? 并不支持
让它俩折中一下,这样来玩。
基于DBUtils实现数据链接池。
模式一:每个线程独立创建自己的链接,无论该线程使用多少次,用的都是同一个。该线程关闭时,伪关闭,本地线程再次调用时,继续使用最开始创建的链接。
何时关闭? 线程不终止,永不关闭!所有线程终止数据库连接,该线程关闭。
模式二:多线程间不分彼此。 创建一个连接池(此处才体现出池),为所有线程提供链接。
使用时从池里获取,使用完毕后,放回连接池。
拿的时候,pop出来,用完再append进去。
连接池里的连接,排队依次被使用。
补充:共享时,可设置最多共享数???
文档里写的可以设置最大共享数,比如我池里有10个线程,最大共享数设置5,你是否认为最多5个可以被来回玩?
NO!源码里面,清清楚楚的写到:大家都是朋友,不见外,一起玩。
pymsql里面的threadsafety=1,代表:无论你如何使用,所有连接都可被重复使用。
本地线程示例:保证每个线程都有数据库连接,都持有自己的一份数据,在操作时,不会相互影响。
import threadingimport time# 本地线程对象local_values = threading.local()def func(num): """ # 第一个线程进来,本地线程对象会为他创建一个 # 第二个线程进来,本地线程对象会为他创建一个 :param num: :return: """ local_values.name = num # 4 # 线程停下来了 time.sleep(2) print(local_values.name, threading.current_thread().name)for i in range(5): th = threading.Thread(target=func, args=(i,), name='线程%s' % i) th.start()
模式二示例:
import timeimport pymysqlimport threadingfrom DBUtils.PooledDB import PooledDB, SharedDBConnectionPOOL = 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='123', database='pooldb', charset='utf8')def func(): # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常 # 否则 # 则优先去初始化时创建的链接中获取链接 SteadyDBConnection。 # 然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。 # 如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。 # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。 # PooledDedicatedDBConnection conn = POOL.connection() # print(th, '链接被拿走了', conn1._con) # print(th, '池子里目前有', pool._idle_cache, '\r\n') cursor = conn.cursor() cursor.execute('select * from tb1') result = cursor.fetchall() conn.close() conn = POOL.connection() # print(th, '链接被拿走了', conn1._con) # print(th, '池子里目前有', pool._idle_cache, '\r\n') cursor = conn.cursor() cursor.execute('select * from tb1') result = cursor.fetchall() conn.close()func()
模式二连接池用法:
import timeimport pymysqlimport threadingfrom DBUtils.PooledDB import PooledDB, SharedDBConnectionPOOL = 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='123', database='pooldb', charset='utf8')
from flask import Flaskfrom db import POOLimport pymysqlapp = Flask(__name__)app.secret_key ='sdfsdfsdf'@app.route('/index')def index(): conn = POOL.connection() cursor = conn.cursor() cursor.execute('select * from tb1') result = cursor.fetchall() conn.close() return '执行成功'if __name__ == '__main__': # app.__call__ app.run()