MySQL连接池

一. 什么是数据库连接池

官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对连接池中的连接进行申请,使用,释放。

理解:创建数据库连接池是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接池,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加的安全可靠。

二. 传统的连接池机制与数据库连接池的运行机制区别

传统链接:一般来说,JAVA应用程序访问数据库的过程:

1) 装载数据库驱动程序;

2) 通过JDBC建立数据库连接;

3) 访问数据库,执行SQL语句;

4) 断开数据库连接;

使用了数据库连接池的机制:

1) 程序初始化时创建连接池;

2) 使用时向数据库申请可用连接;

3) 使用完毕,将连接返回给连接池;

4) 程序退出时,断开所有连接,并释放资源;

一. 为何要使用数据库连接池

假设网站一天有很大的访问量,数据库服务器就需要为每次连接创建一次数据库连接,极大的浪费数据库资源,并且极易造成数据库服务器内存溢出,拓机。

数据库连接池是一种关键的有限的昂贵的资源,这一点在多用户的网页程序中体现的尤为突出,对数据库连接的管理显著影响到整个应用程序的伸缩性和健壮性,影响程序的性能指标,数据库连接池正式针对这个问题提出的。数据库连接池负责分配,管理和释放数据库的连接,它允许应用程序重复使用一个现有的数据库连接,而不是重建一个。

数据库连接池在初始化时创建一定数量的数据库连接放到连接池中,这些数据在连接的数量上是由最小数据库连接数来设定的,无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量,连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数。当应用程序向连接池请求连接数量超过最大连接数量时,这些请求将被加入到等待队列中。

数据库连接池的最小连接数和最大连接数的设置要考虑以下几个因素:

1) 最小连接数:是连接池一直保持数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费。

2) 最大连接数:是连接池能申请的最大连接数,如果数据库的连接请求超过次数,后面的数据库连接将被加入到等待队列中,这会影响以后的数据库操作。

3) 如果最小连接数与最大连接数相差很大,那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接,不过这些大于最小连接数的数据库连接在使用完不会马上被释放,它将放到连接池中等待重复使用或是时间超时后被释放。

二. 使用数据库连接池的关键点

1.并发问题

为了使连接池管理服务具有最大的通用性,必须考虑多线程环境,这个问题相对于好解决,因为各个语言自身提供了对于并发管理的支持,可以保证线程的同步。

2. 事务处理

DB连接池必须要确保某一时间内一个connection只能分配给一个线程。不同conection的事务是相互独立的。

我们知道,事务具有原子性,此时要求对数据库的操作符合原子操作:要么不做,要么全做。

我们知道当2个线程共用一个连接Connection对象,而且各自都有自己的事务要处理的时候,对于连接池 是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定那个数据库操作是对应那个事务的,这是由于我们有两个线程都在进行事务操作而引起的,为此我们可以使用每一个事物独占一个连接来实现,虽然这种方法有点浪费连接池资源但是可以大大降低事物管理的复杂性。

3. 连接池的分配与释放

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

对于连接的管理可使用一个list,即把已经创建的连接都放入list中去同一管理。每当用户请求一个连接时,系统检查这个list中有没有可以分配的连接。如果有,就会把那个最合适的连接分配给他;如果没有就会抛出一个异常给用户,list中连接是否可以被分配有一个线程来专门管理稍后我会介绍这个线程的具体实现。

4. 连接池的配置与维护

连接池到底该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数和最大连接数等参数来控制连接池中的连接。

比如说,最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统的启动很快,响应却慢,这样,在开发时,设置较小的连接池数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过软件需求得到。

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

三. 使用连接池的优势和其工作原理

1.连接池的优势

连接池用于创建和管理数据库连接的缓冲池技术,缓冲池中的连接可以被任何需要他们的线程使用。当一个线程需要用JDBC对一个数据库操作时,将从池中请求一个连接。当这个连接使用完毕后,将返回到连接池中,等待为其他线程服务。

连接池主要只有以下三个方面的优势:

第一、 减少创建连接的时间。连接池中的连接是已准备好的,可重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。

第二、 简化的变成方式。当使用连接池时,每一个单独的线程能够像创建一个自己的JDBC连接一样操作,允许用户直接使用的次数和时间。

第三、 控制资源的使用。 如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平下。连接池能控制池中的连接数量,增强了系统在大量用户应用时的稳定性。

2. 连接池的工作原理

连接池技术的核心思想是连接复用,通过建立一个数据库连接池以及一套连接的使用,分配和管理策略,使得该连接池中的连接可以得到高效,安全的复用,避免数据库连接频繁建立,关闭的开销。

连接池的工作原理主要有三部分组成,分别为连接池的建立,连接池中连接的使用管理,连接池的关闭。

第一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中创建几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建与关闭。这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,如Vector。Stack。

第二、 连接池的管理。 连接池管理策略施连接池机制的核心,连接池内连接的分配和释放都对系统性能有很大的影响。其管理策略是:

- 当用户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没有达到就重新创建一个连接给请求的用户;如果达到就设定最大等待时间进行等待,如果超出最大的等待时间,则抛出异常给用户。

- 当用户释放数据库连接时,先判断该连接的引用次数是否超出规定值,如果超出就从连接池中删除该连接,否则保留为其他客户服务。

该策略保证了数据库连接的有效复用,避免频繁的建立,释放连接所带来的系统资源开销。

第三、连接池关闭。当应用程序退出时,关闭连接池中的所有连接,释放连接池相关的资源,该过程正好与创建相反。

 

程序开发过程中,存在很多问题:

首先,每一次web请求都要建立一次数据库连接,建立连接是一个费时的操作,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。

可是对于现在的web应用,尤其是大型电子商务站,同时有几百人甚至几千人在线是很正常的,在这种情况下,频繁的进行数据库连接势必占用很大的系统资源,网站响应速度势必下降,严重的会导致服务器的崩溃。其次,对每一次数据库连接,使用完后都得断开,否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。

从上面可以看出,数据库连接是一种稀缺资源,我们应对其妥善管理。其实我们查询完数据库后,如果不关闭连接,而是暂时存放起来,当别人使用时把这个连接给他们使用,就避免了一次建立数据库的连接和断开的操作的时间消耗。

数据库连接池的基本思想是:为数据库连接建立一个缓冲池,预先在缓冲池中放入一定数量的连接,当需要建立连接的时候,只需从缓存池中取出一个,使用完后在放回去。

import pymysql
from DBUtils.PooledDB import PooledDB # pip install DBUtils

db_config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "passwd": "root",
    "db": "crm",
    "charset": "utf8"
}

pool = PooledDB(pymysql, 5, **db_config)  # 5为连接池里的最少连接数

conn = pool.connection()  # 以后每次需要数据库连接就是用connection()函数获取连接就好了
cur = conn.cursor()
SQL = "select * from rbac_menu;"
# 执行sql语句
res = cur.execute(SQL)
# 查询所有符合条件的数据
ret = cur.fetchall()
print(ret)
cur.close()
conn.close()

 

posted @ 2020-02-26 10:24  叫我大表哥  阅读(1049)  评论(0编辑  收藏  举报