为什么要使用数据库连接池?以及用法(DBUtils)

看代码,

from flask import Flask
from db import POOL
import pymysql
app = 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 threading
import 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()
local

模式二示例:

import time
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
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='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, '
')

    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, '
')

    cursor = conn.cursor()
    cursor.execute('select * from tb1')
    result = cursor.fetchall()
    conn.close()


func()
PooledDB

模式二连接池用法:

import time
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
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='123',
    database='pooldb',
    charset='utf8'
)
from flask import Flask
from db import POOL
import pymysql
app = 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()
原文地址:https://www.cnblogs.com/Wormhole-f/p/8254499.html