精华内容
下载资源
问答
  • 数据库连接池图解
    2021-04-28 18:52:43

    1 如何在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操作数据库,以及会出现的问题。

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

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

    示例1:

    把所有的数据库操作全部都放在了视图函数里面。

    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='qwer',
                               database='book2',
                               charset='utf8')
    
        cursor = CONN.cursor()
        cursor.execute('select * from good')
        result = cursor.fetchall()
        cursor.close()
    
        print(result)
    
        return "Hello World"
    
    
    if __name__ == '__main__':
        app.run()
    

    会出现的问题

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

    小结:

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

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

    2.2 什么是数据库连接池呢?

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

    图解

    1553241307822

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

    2.3 Python数据库连接池DBUtils

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

    首先安装一下DBUtils模块。

    pip install DBUtils
    

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

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

    import pymysql
    from DBUtils.PersistentDB import PersistentDB
    
    POOL = PersistentDB(
        creator=pymysql,  # 使用链接数据库的模块
        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
        closeable=False,
        # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close(
        # )则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
        threadlocal=None,  # 如果为none,用默认的threading.Local对象,否则可以自己封装一个local对象进行替换
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123456',
        database='book2',
        charset='utf8'
    )
    
    
    def func():
        conn = POOL.connection(shareable=False)
        cursor = conn.cursor()
        cursor.execute('select * from good')
        result = cursor.fetchall()
        print(result)
        cursor.close()
        conn.close()
    
    
    func()
    

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

    import pymysql
    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='qwer',
        database='book2',
        charset='utf8'
    )
    
    
    def func():
        conn = POOL.connection()
        cursor = conn.cursor()
        cursor.execute('select * from good')
        result = cursor.fetchall()
        print(result)
        conn.close()
    
    
    func()
    

    2.3 实际开发小应用案例:

    案例目录:

    - 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 good', [])
        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,  # 连接池允许的最大连接数,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='qwer',
        database='book2',
        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(sql, args):
            conn = POOL.connection()
            cursor = conn.cursor()
            cursor.execute(sql, args)
            result = cursor.fetchall()
            conn.close()
            return result
    

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

    更多相关内容
  • 简单但是非常实用,让你在短时间内掌握数据库对象信息的查找命令,掌握数据库连接池的原理
  • 数据库连接池图解原理
  • Weblogic数据库连接池配置图解

    千次阅读 2018-12-04 10:35:06
    1、建立连接池 2、填写连接属性 3、测试连接配置 4、创建、部署 ...5、在connections面板上进行高级测试属性的配置 ...9、选择数据库源放置与那个连接池 10、选择目标服务器 11、配置成...

    1、建立连接池
    在这里插入图片描述
    2、填写连接属性
    在这里插入图片描述
    3、测试连接配置
    在这里插入图片描述
    4、创建、部署
    在这里插入图片描述
    5、在connections面板上进行高级测试属性的配置
    在这里插入图片描述
    在这里插入图片描述
    选中三个test选项
    在这里插入图片描述
    6、到testing处进行测试
    在这里插入图片描述
    表示在服务器myserver上部署成功
    在这里插入图片描述
    7、到datasources处配置数据源(jndi设置)
    在这里插入图片描述
    8、设置jndi名(重要)
    在这里插入图片描述
    9、选择数据库源放置与那个连接池
    在这里插入图片描述
    10、选择目标服务器
    在这里插入图片描述
    11、配置成功
    在这里插入图片描述
    12、编写简单的web程序测试数据源
    (略)

    展开全文
  • 数据库连接池详解

    2020-11-03 20:39:00
    本文转自谈谈数据库连接池的原理 谈谈数据库连接池的原理 这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。 一.早期我们怎么进行数据库操作 原理:...

    本文转自谈谈数据库连接池的原理
    Mybatis 数据源和数据库连接池源码解析

    谈谈数据库连接池的原理

    这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。

    一.早期我们怎么进行数据库操作

    在这里插入图片描述

    原理:一般来说,java应用程序访问数据库的过程是:

    ①装载数据库驱动程序;

    ②通过jdbc建立数据库连接;

    ③访问数据库,执行sql语句;

    ④断开数据库连接。

    代码

           Public void FindAllUsers(){
                  //1、装载sqlserver驱动对象
                  DriverManager.registerDriver(new SQLServerDriver());             
                  //2、通过JDBC建立数据库连接
                  Connection con =DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer", "sa", "123");            
                  //3、创建状态
                  Statement state =con.createStatement();           
                  //4、查询数据库并返回结果
                  ResultSet result =state.executeQuery("select * from users");           
                  //5、输出查询结果
                  while(result.next()){
                         System.out.println(result.getString("email"));
                  }            
                  //6、断开数据库连接
                  result.close();
                  state.close();
                  con.close();
            }
    
    
    

    分析

    程序开发过程中,存在很多问题:首先,每一次web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

    上述的用户查询案例,如果同时有1000人访问,就会不断的有数据库连接、断开操作:

    在这里插入图片描述

    通过上面的分析,我们可以看出来,“数据库连接”是一种稀缺的资源,为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,如果不关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。原理如下:
    在这里插入图片描述

    二. 技术演进出来的数据库连接池

    由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池(resource pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。

    我们自己尝试开发一个连接池,来为上面的查询业务提供数据库连接服务:

    ① 编写class 实现DataSource 接口

    ② 在class构造器一次性创建10个连接,将连接保存LinkedList中

    ③ 实现getConnection 从 LinkedList中返回一个连接

    ④ 提供将连接放回连接池中方法

    连接池代码

        public class MyDataSource implements DataSource {
                  //链表 --- 实现栈结构
                  privateLinkedList<Connection> dataSources = new LinkedList<Connection>();
     
                  //初始化连接数量
                  publicMyDataSource() {
                         //一次性创建10个连接
                         for(int i = 0; i < 10; i++) {
                                try {
                                   //1、装载sqlserver驱动对象
                                   DriverManager.registerDriver(new SQLServerDriver());
                                   //2、通过JDBC建立数据库连接
                                   Connection con =DriverManager.getConnection(
                                      "jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer", "sa", "123");
                                   //3、将连接加入连接池中
                                   dataSources.add(con);
                                } catch (Exception e) {
                                   e.printStackTrace();
                                }
                         }
                  }
     
                  @Override
                  publicConnection getConnection() throws SQLException {
                         //取出连接池中一个连接
                         finalConnection conn = dataSources.removeFirst(); // 删除第一个连接返回
                         returnconn;
                  }
     
                  //将连接放回连接池
                  publicvoid releaseConnection(Connection conn) {
                         dataSources.add(conn);
                         }
           }
    
    

    使用连接池重构我们的用户查询函数

           //查询所有用户
           Public void FindAllUsers(){
                  //1、使用连接池建立数据库连接
                  MyDataSource dataSource = new MyDataSource();
                  Connection conn =dataSource.getConnection();        
                  //2、创建状态
                  Statement state =con.createStatement();           
                  //3、查询数据库并返回结果
                  ResultSet result =state.executeQuery("select * from users");           
                  //4、输出查询结果
                  while(result.next()){
                         System.out.println(result.getString("email"));
                  }            
                  //5、断开数据库连接
                  result.close();
                  state.close();
                  //6、归还数据库连接给连接池
                  dataSource.releaseConnection(conn);
            }
    
    

    这就是数据库连接池的原理,它大大提供了数据库连接的利用率,减小了内存吞吐的开销。我们在开发过程中,就不需要再关心数据库连接的问题,自然有数据库连接池帮助我们处理,这回放心了吧。但连接池需要考虑的问题不仅仅如此,下面我们就看看还有哪些问题需要考虑。

    三.连接池还要考虑更多的问题

    并发问题

    为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如 public synchronized connection getconnection()

    多数据库服务器和多用户

    对于大型的企业级应用,常常需要同时连接不同的数据库(如连接oracle和sybase)。如何连接不同的数据库呢?我们采用的策略是:设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址等信息。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。

    对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件处理,即在资源文件中设置多个具有相同url地址,但具有不同用户名和密码的数据库连接信息。

    事务处理

    我们知道,事务具有原子性,此时要求对数据库的操作符合“all-all-nothing”原则即对于一组sql语句要么全做,要么全不做。

    在java语言中,connection类本身提供了对事务的支持,可以通过设置connection的autocommit属性为false 然后显式的调用commit或rollback方法来实现。但要高效的进行connection复用,就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现,这种方法可以大大降低事务管理的复杂性。

    连接池的分配与释放

    连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。

    一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxconn)如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout 则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法。

    连接池的配置与维护

    连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minconn)和最大连接数(maxconn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过反复测试,找到最佳点。

    如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。

    展开全文
  • Flask数据库连接池

    2021-06-10 17:44:06
    08.Flask数据库连接池 文章目录08.Flask数据库连接池一、flask-session作用安装基本使用问题:二、如何在python中操作数据库在web中使用原生sql(pymysql)操作数据库?在web中通过原生sql操作数据库会出现的问题示例...

    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)
    #use_signer是否对key签名
    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)#这样设置即可
    #在session中设置
    app.session_interface=RedisSessionInterface(conn,key_prefix='lqz',permanent=False)
    #一般不用,我们一般都设置超时时间,多长时间后失效
    
    • 问题2:cookie默认超时时间是多少?如何设置超时时间
    #源码expires = self.get_expiration_time(app, session)
    '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的并发,这个时候最终的解决方案是数据库连接池。

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

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

    图解

    1553241307822

    通俗的讲就是,假设数据库连接池中有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,  # 一个链接最多被重复使用的次数,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
        closeable=False,
        # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
        threadlocal=None,  # 如果为none,用默认的threading.Loacl对象,否则可以自己封装一个local对象进行替换
        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,  # 连接池允许的最大连接数,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():
        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,  # 连接池允许的最大连接数,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'
    )
    
    
    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,来实现自己个性化操作数据库的需求。

    展开全文
  • JDBC 和数据库连接池

    千次阅读 2022-01-24 20:33:59
    Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。 JDBC的基本原理图【重要!】 模拟JDBC package com.xjs.jdbc.myjdbc; /** * @author 谢家升 * @version ...
  • mybatis数据库连接池分析介绍 一、数据库连接池 1、定义 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库...
  • 01 如何在python中操作数据库?在后端开发中免不掉与数据库打交道,无非是使用orm或者原生sql来操作数据库。在python中通过原生sql操作数据库,主流就两种。使用pymysql模块:pymysql支持python2.x和python3.x的版本...
  • hikari简介以及相关的概念"Simplicity is prerequisite for reliability."- Edsger Dijkstrahikari,日语中“光”的意思,作者为这个数据库连接池命名为光,寓意是像光一样快。在分析hikariCP之前简单介绍下JDBC和...
  • 数据库连接池

    千次阅读 2020-03-20 21:32:56
    文章目录数据库连接池一、 如何在python中操作数据库?二、 在web中使用原生sql(pymysql)操作数据库?2.1 在web中通过原生sql操作数据库会出现的问题。示例1:示例2示例3小结:2.1 什么是数据库连接池呢?2.2 Python...
  • 1 连接池的基本工作原理  基本概念及原理  由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池 (Resource Pool)。该模式正是...
  • 数据库连接池的原理

    2019-07-22 15:53:03
    数据库连接池原理: 图解: 连接池原理:
  • JDBC——(8)数据库连接池技术的概述——Druid数据库连接池技术的实现 JDBC——小知识:Druid连接池的详细配置参数 Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点...
  • 数据库连接池知识

    2020-04-06 20:58:25
    数据库连接池 什么是数据库连接池? 在JDBC编程中,每次创建和断开Connection对象都会消耗一定的时间和IO资源。这是因为在java程序与数据库之间建立链接时,数据库端要验证用户名和密码,并且要为这个链接分配...
  • 文章目录一,JDBC数据库连接池的必要性二, 数据库连接池技术三,工作原理四,数据库连接池技术的优点五,多种开源的数据库连接池 一,JDBC数据库连接池的必要性 在使用开发基于数据库的web程序时,传统的模式基本...
  • 简单介绍一下数据库概念 1.数据库(Database) 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,当前使用最多的是关系型数据库,常见数据库软件包括:oracle,mysql,postgresql,DB2,SQL SERVER.... ...
  • 数据库连接池图解原理
  • mysql数据库连接池配置教程第一步:写javabeanpackage withouttears.jdbc.db;import java.util.HashMap;import java.sql.*;//JNDI有两个核心接口Context和DirContext,//Context中包含了基本的名字操作,而...
  • JDBC数据库连接池详解

    2019-06-20 16:07:56
    数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来...
  • 本文利用Tomcat5配置Mysql JDBC数据库连接池,并给出详细的测试用例。 @author:ZJ07-11-23 Blog:[url]http://zhangjunhd.blog.51cto.com/[/url] 1.配置说明 Tomcat5.0 Eclipse3.3+MyEclipse6.0 Mysql5 mysql-...
  • 数据库事务、事务属性。DAO及其子类、事务操作、数据库连接池、C3P0连接池、DBCP连接池、DBUtils包及其CRUD操作
  • DataSource通常被称为数据源,它包含连接池连接池管理两个部分,习惯上也经常把DataSource称为连接池。  JNDI方式创建DataSource: (JavaNamingandDirectoryInterface,Java命名和目录接口)。首先要配...
  • 其实操作flask的请求上下文就是操作Local中的字典通过REquestContext类首先实例化ctx请求上下文对象,其内部包含请求对象入栈,通过请求上下文对象的类的push()方法触发了LocalStack类的...数据库连接池概念图解。...
  • 概念数据库连接是一种关键的有限的昂贵的资源 物理连接统一由连接池管理,减少数据库连接释放的压力 :) 每次请求每次新建一个逻辑连接,实际是复用连接池的物理...图解参考由数据库连接池引出的三种设计模式
  • 数据库连接池的使用

    2019-09-15 16:02:37
    数据库连接池proxool的使用 浅析数据库连接池 什么是数据库连接池?为什么要使用数据库连接池?这是我们看到数据库连接池首先想到的问题。下面笔者将对数据库连接池以自己的理解进行简单的分析。 数据库连接池:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,523
精华内容 1,409
热门标签
关键字:

数据库连接池图解