Flask数据库连接池

08.Flask数据库连接池

文章目录

一、flask-session

作用

  • 将默认保存的签名cookie中的值 保存到 redis/memcached/file/Mongodb/SQLAlchemy

安装

pip3 install flask-session

基本使用

使用一:

from flask import Flask,session
from flask_session import RedisSessionInterface
import redis
app = Flask(__name__)
conn=redis.Redis(host='127.0.0.1',port=6379)

app.session_interface=RedisSessionInterface(conn,key_prefix='lqz')
@app.route('/')
def hello_world():
    session['name']='lqz'
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

使用二:

from redis import Redis
from flask.ext.session import Session
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='6379')
Session(app)

问题:

  • 问题1:设置cookie时,如何设定关闭浏览器则cookie失效。
response.set_cookie('k','v',exipre=None)

app.session_interface=RedisSessionInterface(conn,key_prefix='lqz',permanent=False)

  • 问题2:cookie默认超时时间是多少?如何设置超时时间

'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),

二、如何在python中操作数据库

在后端开发中免不掉与数据库打交道,无非是使用 orm或者原生 sql来操作数据库。

在python中通过原生sql操作数据库,主流就两种。

  • 使用pymysql模块: pymysql支持 python2.xpython3.x的版本
  • 使用mysqldb模块: mysqldb仅支持 python2.x的版本

orm的使用以flask和django为例。

  • flask使用的orm是基于 SQLAlchemy(SQLAlchemy本就是orm),flask团队并在 SQLAlchemy基础之上又封装了一个 Flask-SQLchemy并予以应用 。
  • django使用的orm是django自带的orm。

orm的操作数据库的方式我们已经熟知了,这里我们聊一聊如何在web中使用原生sql操作数据库,以及会出现的问题。

在web中使用原生sql(pymysql)操作数据库?

在web中通过原生sql操作数据库会出现的问题

示例一:
  • 把所有的数据库操作全部都放在了视图函数里面
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    import pymysql
    CONN = pymysql.connect(host='127.0.0.1',
                           port=3306,
                           user='root',
                           password='123',
                           database='pooldb',
                           charset='utf8')

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

    print(result)

    return "Hello World"

if __name__ == '__main__':
    app.run()

会出现的问题:

  • 很多个用户并发的来请求,一个用户可以理解为一个线程,每个线程都会跟数据库建立连接,数据库承受不了这种量级的连接数。
示例二:
  • 为了避免之前每个用户都建立连接,我们把数据库连接放到了全局变量里面,只会建立一次连接,但是依然会出现问题。
from flask import Flask

app = Flask(__name__)
import pymysql
CONN = pymysql.connect(host='127.0.0.1',
                           port=3306,
                           user='root',
                           password='123',
                           database='pooldb',
                           charset='utf8')

@app.route("/")
def hello():
    cursor = CONN.cursor()
    cursor.execute('select * from tb1')
    result = cursor.fetchall()
    cursor.close()

    print(result)

    return "Hello World"

if __name__ == '__main__':
    app.run()

会出现的问题:

  • 会出现线程安全问题,比如如果第一个用户拿到了连接给关闭了,而第二个用户正在进行查询,第二个用户查询的时候第一个用户把连接断了,会导致第二个用户出现问题。
  • 假设第一用户查询了一下表1,正准备获取查询的内容,这时第二个人查询了一下表2,由于cursor对象都是同一个,第一个人获取到的查询内容就是表2的内容了,所以也会出现线程安全问题
示例三:
  • 为了避免之前的线程不安全,在示例2的基础上加上一把线程锁
from flask import Flask
import threading
app = Flask(__name__)
import pymysql
CONN = pymysql.connect(host='127.0.0.1',
                           port=3306,
                           user='root',
                           password='123',
                           database='pooldb',
                           charset='utf8')

@app.route("/")
def hello():
    with threading.Lock():
        cursor = CONN.cursor()
        cursor.execute('select * from tb1')
        result = cursor.fetchall()
        cursor.close()

        print(result)

    return "Hello World"

if __name__ == '__main__':
    app.run()

会出现的问题:

  • 根据代码可以发现,只是在示例2的基础上加了一把线程锁,确实是保证了线程安全,但是所有关于数据库操作的请求变成了串行,无法实现并发了。

小结

  • 如果直接连接坐在视图函数中,会导致每个用户都要创建连接,数据库承受不了这种量级的连接数。
  • 如果连接数据库的内容做成全局变量的话,无法保证线程安全。
  • 如果定义全局变量用于连接数据库,并且在线程中操作数据库内容加线程锁头,就会变成串行,无法保证并发

所以我们既要控制数据库的连接数,又要保证线程安全,又要保证web的并发,这个时候最终的解决方案是数据库连接池。

三、什么是数据库连接池呢?

数据库连接池概念:数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个,这项技术能明显提高对数据库操作的性能。

图解

Flask数据库连接池

通俗的讲就是,假设数据库连接池中有5个连接对象,每个用户简单理解为一个线程,比如现在有6个用户同时来访问,6个线程去数据库连接池里面申请数据库的连接对象。前5个线程每个都申请到了连接对象去操作数据库,每个线程使用完了数据库连接对象会归还给数据库连接池,那么第6个线程会等待前5个线程归还连接对象给连接池,再具体一点是:假设第一个线程使用完了连接对象,那么此时6个线程才会结束等待,从而申请到连接对象,以此类推。

; Python数据库连接池DBUtiles

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

首先安装一下DBUtils模块

pip install DBUtils

DBUtils连接池的两种连接模式:

模式一:为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,仅供自己的线程再次使用,当线程终止时,连接会自动关闭。(不推荐使用,因为这样需要自己控制线程数量)

import pymysql
from DBUtils.PersistentDB import PersistentDB
from threading import local

POOL = PersistentDB(
    creator=pymysql,
    maxusage=None,
    setsession=[],
    ping=0,
    closeable=False,

    threadlocal=None,
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='pooldb',
    charset='utf8'
)

def func():
    conn = POOL.connection(shareable=False)
    cursor = conn.cursor()
    cursor.execute('select * from tb1')
    result = cursor.fetchall()
    cursor.close()
    conn.close()

func()

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

import time
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
POOL = PooledDB(
    creator=pymysql,
    maxconnections=6,
    mincached=2,
    maxcached=5,
    maxshared=3,
    blocking=True,
    maxusage=None,
    setsession=[],
    ping=0,

    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='pooldb',
    charset='utf8'
)

def func():
    conn = POOL.connection()
    cursor = conn.cursor()
    cursor.execute('select * from tb1')
    result = cursor.fetchall()
    conn.close()

func()

实际开发小应用案例

案例目录:

- app.py
- db_helper.py

app.py

from flask import Flask
from db_helper import SQLHelper

app = Flask(__name__)

@app.route("/")
def hello():
    result = SQLHelper.fetch_one('select * from t1',[])
    print(result)
    return "Hello World"

if __name__ == '__main__':
    app.run()

db_helper.py

import pymysql
from DBUtils.PooledDB import PooledDB
POOL = PooledDB(
    creator=pymysql,
    maxconnections=6,
    mincached=2,
    maxcached=5,
    maxshared=3,
    blocking=True,
    maxusage=None,
    setsession=[],
    ping=0,

    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='pooldb',
    charset='utf8'
)

class SQLHelper(object):

    @staticmethod
    def fetch_one(sql,args):
        conn = POOL.connection()
        cursor = conn.cursor()
        cursor.execute(sql, args)
        result = cursor.fetchone()
        conn.close()
        return result

    @staticmethod
    def fetch_all(self,sql,args):
        conn = POOL.connection()
        cursor = conn.cursor()
        cursor.execute(sql, args)
        result = cursor.fetchall()
        conn.close()
        return result

以后在开发的过程中我们可以基于数据库连接池,基于pymysql,来实现自己个性化操作数据库的需求。

Original: https://blog.csdn.net/weixin_44621343/article/details/117787807
Author: 淘小欣
Title: Flask数据库连接池

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/747390/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球