1. 连接池的实现原理
1. 创建连接池
首先要创建一个静态的连接池。这里的“静态”是指池中的连接时在系统初始化时就分配好的,并且不能够随意关闭。Java 提供了很多容器类可用来构建连接池,例如Vector、Stack等。在系统初始化时,根据配置创建连接并放置在连接池中,以后所使用的连接都是从该连接池中获取的,这样就可以避免连接随意建立、关闭造成的开销。
2. 分配、释放策略
创建好连接池后,需要提供一套自定义的分配、创建策略以保证数据库连接的有效复用。当客户请求数据库连接时,首先看连接池中是否有空闲连接(目前没有分配出去的连接),如果存在空闲连接则把连接分配给客户,并做相应的处理;若连接池中没有空闲连接,就在已经分配出去的连接中,寻找一个合适的连接给客户,此时该连接在多个客户间复用。当客户释放数据库连接时,可以根据该连接是否被复用,进行不同的处理。如果连接没有使用者,就放入到连接池中,而不是关闭。
分配、释放策略对于有效复用连接非常重要。Reference Countiong(引用记数)时一种复用资源方面应用的非常广泛的方法,这里将该方法运用到对于连接的分配释放上。使用连接池时,为每一个数据库连接保留一个引用记数,用来记录该连接的使用者的个数。在具体的实现上,可以采用两级连接池:空闲池和使用池。空闲池中存放目前还没有分配出去被使用的连接,一旦一个连接被分配出去,那么就会放入到使用池中,并增加引用记数。这样做可以更高效地使用连接,一旦空闲池中的连接被全部分配出去,就可以根据相应的策略从使用池中挑选出一个已经正在使用的连接来复用,而不是随意拿出一个连接去复用。策略可以根据需要去选择,比较简单的做法时复用引用记数最小的连接。Java的面向对象特性,使得可以灵活地选择不同的策略(提供一个不同策略共用的抽象接口,各个具体的策略都实现这个接口,这样对于策略的处理逻辑和策略的实现逻辑分离)。
3. 配置策略
数据库连接池中到底要放置多少个连接,连接耗尽后应该如何处理,这就时配置策略需要解决的问题。在一般情况下,配置策略在开始时就根据具体的应用需求,给出一个初始的连接池中的连接的数目以及一个连接池可以扩张到的最大连接数目。
2. 在Tomcat上配置数据源与连接池
1. 配置Tomcat的连接池:配置Server.xml文件。首先打开 omcatconf目录下的Server.xml文件,然后在其</host>标签前面添加如下代码
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> <Context> <Resource name="jdbc/my_db" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/ch10" username="root" password="root" maxActive="20" maxIdle="10" maxWait="-1"/> </Context> </Host>
path:制定路径。这里设定的时/CATALINA_HOME/webapps下的DBTest目录。
docBase : 制定应用程序文件根目录。
reloadable : 设定当网页被更新时是否重新编译。
maxActive : 设定连接池的最大数据库连接数,设为0标识没有连接数限制。
maxIdle : 设定数据库最大空闲时间,超过此空闲时间,数据库连接将被标记为不可用,然后被释放,设为0表示没有限制。
maxWait : 设定最大建立连接等待时间,如果超过此时间将接到异常,设为-1表示没有限制。
username : 访问数据库的用户名。
password : 访问数据库的密码。
driverClassName : 数据库的JDBC驱动程序名称。
url : 数据库连接串
2. 配置web服务:配置web.xml文件。
<resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/my_db</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
description : 对被引用资源的描述。
res-ref-name : 引用的资源名称。
res-type : 引用的资源的类型,这里时Server.xml中配置的数据源。
3. 编写测试页面Test.jsp。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.sql.*,javax.naming.*,java.sql.*" errorPage="" %> <%@ page import="javax.sql.DataSource" %> <html> <head> <title>Title</title> </head> <body> <% out.print("使用连接池连接Derby数据库成功!<br>");//输出提示信息 out.println("<br>"); Context ctx = null; DataSource ds = null; Statement stmt = null; ResultSet rs = null; Connection con = null; ResultSetMetaData md = null; try{ ctx = new InitialContext(); ds = (DataSource)ctx.lookup("java:comp/env/jdbc/limeDB");//找到配置的数据源 con = ds.getConnection();//创建数据库连接 stmt = con.createStatement(); rs = stmt.executeQuery("SELECT * FROM student"); md = rs.getMetaData(); out.print(md.getColumnLabel(1) + " "); out.print(md.getColumnLabel(2) + " "); out.print(md.getColumnLabel(3) + " "); out.print(md.getColumnLabel(4) + "<br>"); while (rs.next()){ out.print(rs.getInt(1) + " "); out.print(rs.getInt(2) + " "); out.print(rs.getInt(3) + " "); out.print(rs.getInt(4) + "<br>"); } }catch (Exception e){ out.print(e); }finally{ if(rs != null)rs.close(); if(stmt != null)stmt.close(); if(con != null)con.close();//断开数据库连接 if(ctx != null)ctx.close();//没有连接时,释放资源 } %> </body> </html>
在Tomcat中配置好数据源后,Tomcat会将这个数据源绑定到JNDI名称空间,然后通过Context.lookup()方法来查找到这个数据源,找到数据源之后,使用getConnection()方法创建一个数据库连接,之后就可以像使用JDBC直接连接数据库那样操作数据库了。
注意:
记得释放资源,尤其时Context资源。
3. 配置连接池时需要注意的问题
1. 最小连接数时连接池一直保存的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费。
2. 最大连接数时连接能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这回影响之后的数据库操作。
3. 如果最小连接数与最大连接数相差太大,那么最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接,这些大于最小连接数的数据库连接在使用完之后不会马上被释放,而是被放到连接池中等待重复使用或是空闲超时后被释放。
啦啦啦
啦啦啦
啦啦啦
啦啦啦
啦啦啦