zoukankan      html  css  js  c++  java
  • 为什么要使用数据库连接池?以及用法(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()
  • 相关阅读:
    POJ 1611 The Suspects
    POJ 2001 Shortest Prefixes(字典树)
    HDU 1251 统计难题(字典树 裸题 链表做法)
    G++ C++之区别
    PAT 乙级 1013. 数素数 (20)
    PAT 乙级 1012. 数字分类 (20)
    PAT 乙级 1009. 说反话 (20)
    PAT 乙级 1008. 数组元素循环右移问题 (20)
    HDU 6063 17多校3 RXD and math(暴力打表题)
    HDU 6066 17多校3 RXD's date(超水题)
  • 原文地址:https://www.cnblogs.com/Wormhole-f/p/8254499.html
Copyright © 2011-2022 走看看