数据库连接池概述
数据库连接是一种关键的有限的昂贵的资源 这一点在多用户的网页应用程序中体现得尤为突出 对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性 影响到程序的性能指标 数据库连接池正是针对这个问题提出来的
数据库连接池负责分配 管理和释放数据库连接 它允许应用程序重复使用一个现有的数据库连接 而再不是重新建立一个 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏 这项技术能明显提高对数据库 *** 作的性能
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中 这些数据库连接的数量是由最小数据库连接数来设定的 无论这些数据库连接是否被使用 连接池都将一直保证至少拥有这么多的连接数量 连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数 当应用程序向连接池请求的连接数超过最大连接数量时 这些请求将被加入到等待队列中 数据库连接池的最小连接数和最大连接数的设置要考虑到下列几个因素
) 最小连接数是连接池一直保持的数据库连接 所以如果应用程序对数据库连接的使用量不大 将会有大量的数据库连接资源被浪费
) 最大连接数是连接池能申请的最大连接数 如果数据库连接请求超过此数 后面的数据库连接请求将被加入到等待队列中 这会影响之后的数据库 *** 作
) 如果最小连接数与最大连接数相差太大 那么最先的连接请求将会获利 之后超过最小连接数量的连接请求等价于建立一个新的数据库连接 不过 这些大于最小连接数的数据库连接在使用完不会马上被释放 它将被放到连接池中等待重复使用或是空闲超时后被释放
目前常用的连接池有 C P DBCP Proxool
网上的评价是
C P 比较耗费资源 效率方面可能要低一点
DBCP在实践中存在BUG 在某些种情会产生很多空连接不能释放 Hibernate 已经放弃了对其的支持
Proxool的负面评价较少 现在比较推荐它 而且它还提供即时监控连接池状态的功能 便于发现连接泄漏的情况
配置如下
在spring配置文件中 一般在applicationContext xml中
<bean id= DataSource class= logicalcobwebs proxool ProxoolDataSource destroy method= shutdown >
<property name= driver >
<value>oracle jdbc driver OracleDriver</value>
</property>
<property name= driverUrl >
<value>jdbc:oracle:thin:xxxx/xxxx@ XX: :server</value>
</property>
<property name= user >
<value>xxxx</value>
</property>
<property name= password >
<value>xxxx</value>
</property>
<property name= alias >
<value>server</value>
</property>
<property name= houseKeepingSleepTime >
<value></value>
</property>
<property name= houseKeepingTestSql >
<value>select from dual</value>
</property>
<property name= testBeforeUse >
<value>true</value>
</property>
<property name= testAfterUse >
<value>true</value>
</property>
<property name= prototypeCount >
<value></value>
</property>
<property name= maximumConnectionCount >
<value></value>
</property>
<property name= minimumConnectionCount >
<value></value>
</property>
<property name= statistics >
<value>m m d</value>
</property>
<property name= statisticsLogLevel >
<value>ERROR</value>
</property>
<property name= trace >
<value>true</value>
</property>
<property name= verbose >
<value>false</value>
</property>
<property name= simultaneousBuildThrottle >
<value></value>
</property>
<property name= maximumActiveTime >
<value></value>
</property>
<property name= jmx >
<value>false</value>
</property>
</bean>
然后注入到sessionFactory中
<bean id= sessionFactory class= springframework orm hibernate LocalSessionFactoryBean >
<property name= dataSource ref= DataSource />
</bean>
属性列表说明:
fatal sql exception: 它是一个逗号分割的信息片段 当一个SQL异常发生时 他的异常信息将与这个信息片段进行比较 如果在片段中存在 那么这个异常将被认为是个致命错误(Fatal SQL Exception ) 这种情况下 数据库连接将要被放弃 无论发生什么 这个异常将会被重掷以提供给消费者 用户最好自己配置一个不同的异常来抛出
fatal sql exception wrapper class:正如上面所说 你最好配置一个不同的异常来重掷 利用这个属性 用户可以包装SQLException 使他变成另外一个异常 这个异常或者继承QLException或者继承字RuntimeException proxool自带了 个实现: logicalcobwebs proxool FatalSQLException 和 logicalcobwebs proxool FatalRuntimeException 后者更合适
house keeping sleep time: house keeper 保留线程处于睡眠状态的最长时间 house keeper 的职责就是检查各个连接的状态 并判断是否需要销毁或者创建
house keeping test sql: 如果发现了空闲的数据库连接 house keeper 将会用这个语句来测试 这个语句最好非常快的被执行 如果没有定义 测试过程将会被忽略
injectable connection interface: 允许proxool实现被代理的connection对象的方法
injectable statement interface: 允许proxool实现被代理的Statement 对象方法
injectable prepared statement interface: 允许proxool实现被代理的PreparedStatement 对象方法
injectable callable statement interface: 允许proxool实现被代理的CallableStatement 对象方法
jmx: 如果属性为true 就会注册一个消息Bean到jms服务 消息Bean对象名: Proxool:type=Pool name=<alias>默认值为false
jmx agent id: 一个逗号分隔的JMX代理列表(如使用MBeanServerFactory findMBeanServer(String agentId)注册的连接池 )这个属性是仅当 jmx 属性设置为 true 才有效 所有注册jmx服务器使用这个属性是不确定的
jndi name: 数据源的名称
maximum active time: 如果housekeeper 检测到某个线程的活动时间大于这个数值 它将会杀掉这个线程 所以确认一下你的服务器的带宽 然后定一个合适的值 默认是 分钟
maximum connection count: 最大的数据库连接数
maximum connection lifetime: 一个线程的最大寿命
minimum connection count: 最小的数据库连接数
overload without refusal lifetime: 这可以帮助我们确定连接池的状态 如果我们已经拒绝了一个连接在这个设定值(毫秒) 然后被认为是超载 默认为 秒
prototype count: 连接池中可用的连接数量 如果当前的连接池中的连接少于这个数值 新的连接将被建立(假设没有超过最大可用数) 例如 我们有 个活动连接 个可用连接 而我们的prototype count是 那么数据库连接池将试图建立另外 个连接 这和 minimum connection count不同 minimum connection count把活动的连接也计算在内 prototype count 是spare connections 的数量
recently started threshold: 这可以帮助我们确定连接池的状态 连接数少还是多或超载 只要至少有一个连接已开始在此值(毫秒)内 或者有一些多余的可用连接 那么我们假设连接池是开启的 默认为 秒
simultaneous build throttle: 这是我们可一次建立的最大连接数 那就是新增的连接请求 但还没有可供使用的连接 由于连接可以使用多线程 在有限的时间之间建立联系从而带来可用连接 但是我们需要通过一些方式确认一些线程并不是立即响应连接请求的 默认是
statistics: 连接池使用状况统计 参数 s m d
statistics log level: 日志统计跟踪类型 参数 ERROR 或 INFO
test before use: 如果为true 在每个连接被测试前都会服务这个连接 如果一个连接失败 那么将被丢弃 另一个连接将会被处理 如果所有连接都失败 一个新的连接将会被建立 否则将会抛出一个SQLException异常
test after use: 如果为true 在每个连接被测试后都会服务这个连接 使其回到连接池中 如果连接失败 那么将被废弃
trace: 如果为true 那么每个被执行的SQL语句将会在执行期被log记录(DEBUG LEVEL) 你也可以注册一个ConnectionListener (参看ProxoolFacade)得到这些信息
lishixinzhi/Article/program/Java/ky/201311/28572连接先建立一些连接,并且这些连接允许共享,因此这样就节省了每次连接的时间开销。Mysql数据库为例,连接池在Tomcat中的配置与使用。
1、创建数据库Student,表student
2、配置server.xml文件。Tomcat安装目录下conf中server.xml文件。
<GlobalNamingResources>
<Resource
name="jdbc/DBPool"
type="javax.sql.DataSource"
password=""
driverClassName="com.mysql.jdbc.Driver"
maxIdle="2"
maxWait="5000"
username="root"
url="jdbc:mysql://localhost:3306/student"
maxActive="3"
/>
</GlobalNamingResources>
name:指定连接池的名称
type:指定连接池的类,他负责连接池的事务处理
url:指定要连接的数据库
driverClassName:指定连接数据库使用的驱动程序
username:数据库用户名
password:数据库密码
maxWait:指定最大建立连接等待时间,如果超过此时间将接到异常
maxIdle:指定连接池中连接的最大空闲数
maxActive:指定连接池最大连接数
3、配置web.xml文件。
<web-app>
<resource-ref>
<description>mysql数据库连接池配置</description>
<res-ref-name>jdbc/DBPool</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
</web-app>
4、配置context.xml文件
与server.xml文件所在的位置相同。
<Context>
<ResourceLink
name="jdbc/DBPool"
type="javax.sql.DataSource"
global="jdbc/DBPool"
/>
</Context>
5、测试
DataSource pool = null
Context env = null
Connection conn = null
Statement st = null
ResultSet rs = null
try{
env = (Context)new InitialContext().lookup("java:comp/env")
//检索指定的对象,返回此上下文的一个新实例
pool = (DataSource)env.lookup("jdbc/DBPool")
//获得数据库连接池
if(pool==null){out.printl("找不到指定的连接池!")}
con = pool.getConnection()
st = con.createStatement()
rs = st.executeQuery("select * from student")
}catch(Exception ex){out.printl(ne.toString())}
开始本文之前,我们看一段Go连接数据库的代码:
本文内容我们将解释连接池背后是如何工作的,并 探索 如何配置数据库能改变或优化其性能。
转自:https://www.jianshu.com/p/cbfc398bd4d6
整理:地鼠文档:www.topgoer.cn
那么sql.DB连接池是如何工作的呢?
需要理解的最重要一点是,sql.DB池包含两种类型的连接——“正在使用”连接和“空闲”连接。当您使用连接执行数据库任务(例如执行SQL语句或查询行)时,该连接被标记为正在使用,任务完成后,该连接被标记为空闲。
当您使用Go执行数据库 *** 作时,它将首先检查池中是否有可用的空闲连接。如果有可用的连接,那么Go将重用这个现有连接,并在任务期间将其标记为正在使用。如果在您需要空闲连接时池中没有空闲连接,那么Go将创建一个新的连接。
当Go重用池中的空闲连接时,与该连接有关的任何问题都会被优雅地处理。异常连接将在放弃之前自动重试两次,这时Go将从池中删除异常连接并创建一个新的连接来执行该任务。
连接池有四个方法,我们可以使用它们来配置连接池的行为。让我们一个一个地来讨论。
SetMaxOpenConns()方法允许您设置池中“打开”连接(使用中+空闲连接)数量的上限。默认情况下,打开的连接数是无限的。
一般来说,MaxOpenConns设置得越大,可以并发执行的数据库查询就越多,连接池本身成为应用程序中的瓶颈的风险就越低。
但让它无限并不是最好的选择。默认情况下,PostgreSQL最多100个打开连接的硬限制,如果达到这个限制的话,它将导致pq驱动返回”sorry, too many clients already”错误。
为了避免这个错误,将池中打开的连接数量限制在100以下是有意义的,可以为其他需要使用PostgreSQL的应用程序或会话留下足够的空间。
设置MaxOpenConns限制的另一个好处是,它充当一个非常基本的限流器,防止数据库同时被大量任务压垮。
但设定上限有一个重要的警告。如果达到MaxOpenConns限制,并且所有连接都在使用中,那么任何新的数据库任务将被迫等待,直到有连接空闲。在我们的API上下文中,用户的HTTP请求可能在等待空闲连接时无限期地“挂起”。因此,为了缓解这种情况,使用上下文为数据库任务设置超时是很重要的。我们将在书的后面解释如何处理。
SetMaxIdleConns()方法的作用是:设置池中空闲连接数的上限。缺省情况下,最大空闲连接数为2。
理论上,在池中允许更多的空闲连接将增加性能。因为它减少了从头建立新连接发生概率—,因此有助于节省资源。
但要意识到保持空闲连接是有代价的。它占用了本来可以用于应用程序和数据库的内存,而且如果一个连接空闲时间过长,它也可能变得不可用。例如,默认情况下MySQL会自动关闭任何8小时未使用的连接。
因此,与使用更小的空闲连接池相比,将MaxIdleConns设置得过高可能会导致更多的连接变得不可用,浪费资源。因此保持适量的空闲连接是必要的。理想情况下,你只希望保持一个连接空闲,可以快速使用。
另一件要指出的事情是MaxIdleConns值应该总是小于或等于MaxOpenConns。Go会强制保证这点,并在必要时自动减少MaxIdleConns值。
SetConnMaxLifetime()方法用于设置ConnMaxLifetime的极限值,表示一个连接保持可用的最长时间。默认连接的存活时间没有限制,永久可用。
如果设置ConnMaxLifetime的值为1小时,意味着所有的连接在创建后,经过一个小时就会被标记为失效连接,标志后就不可复用。但需要注意:
理论上,ConnMaxLifetime为无限大(或设置为很长生命周期)将提升性能,因为这样可以减少新建连接。但是在某些情况下,设置短期存活时间有用。比如:
如果您决定对连接池设置ConnMaxLifetime,那么一定要记住连接过期(然后重新创建)的频率。例如,如果连接池中有100个打开的连接,而ConnMaxLifetime为1分钟,那么您的应用程序平均每秒可以杀死并重新创建多达1.67个连接。您不希望频率太大而最终影响性能吧。
SetConnMaxIdleTime()方法在Go 1.15版本引入对ConnMaxIdleTime进行配置。其效果和ConnMaxLifeTime类似,但这里设置的是:在被标记为失效之前一个连接最长空闲时间。例如,如果我们将ConnMaxIdleTime设置为1小时,那么自上次使用以后在池中空闲了1小时的任何连接都将被标记为过期并被后台清理 *** 作删除。
这个配置非常有用,因为它意味着我们可以对池中空闲连接的数量设置相对较高的限制,但可以通过删除不再真正使用的空闲连接来周期性地释放资源。
所以有很多信息要吸收。这在实践中意味着什么?我们把以上所有的内容总结成一些可行的要点。
1、根据经验,您应该显式地设置MaxOpenConns值。这个值应该低于数据库和 *** 作系统对连接数量的硬性限制,您还可以考虑将其保持在相当低的水平,以充当基本的限流作用。
对于本书中的项目,我们将MaxOpenConns限制为25个连接。我发现这对于小型到中型的web应用程序和API来说是一个合理的初始值,但理想情况下,您应该根据基准测试和压测结果调整这个值。
2、通常,更大的MaxOpenConns和MaxIdleConns值会带来更好的性能。但是,效果是逐渐降低的,而且您应该注意,太多的空闲连接(连接没有被复用)实际上会导致性能下降和不必要的资源消耗。
因为MaxIdleConns应该总是小于或等于MaxOpenConns,所以对于这个项目,我们还将MaxIdleConns限制为25个连接。
3、为了降低上面第2点的风险,通常应该设置ConnMaxIdleTime值来删除长时间未使用的空闲连接。在这个项目中,我们将设置ConnMaxIdleTime持续时间为15分钟。
4、ConnMaxLifetime默认设置为无限大是可以的,除非您的数据库对连接生命周期施加了硬限制,或者您需要它协助一些 *** 作,比如优雅地交换数据库。这些都不适用于本项目,所以我们将保留这个默认的无限制配置。
与其硬编码这些配置,不如更新cmd/api/main.go文件通过命令行参数读取配置。
ConnMaxIdleTime值比较有意思,因为我们希望它传递一段时间,最终需要将其转换为Go的time.Duration类型。这里有几个选择:
1、我们可以使用一个整数来表示秒(或分钟)的数量,并将其转换为time.Duration。
2、我们可以使用一个表示持续时间的字符串——比如“5s”(5秒)或“10m”(10分钟)——然后使用time.ParseDuration()函数解析它。
3、两种方法都可以很好地工作,但是在这个项目中我们将使用选项2。继续并更新cmd/api/main.go文件如下:
File: cmd/api/main.go
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)