數據庫連接是一種關鍵的有限的昂貴的資源,這在多用戶網頁應用程序中體現的尤為突出.對數據庫連接的管理能顯著影響到整個應用程序的伸縮性和健壯性,影響到程序的性能指標,數據庫連接池正是針對這個問題提出的.
數據庫連接池負責分配,管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而不是再重新建立一個;釋放空閑時間超過最大空閑時間的數據庫連接來避免因為沒有釋放數據庫連接而引起的數據庫連接遺漏,這樣可以明顯提高對數據庫操作的性能.
數據庫連接池在初始化的時將創建一定數量的數據庫連接放到連接池中,這些數據庫連接的數量是又最小數據庫連接數來設定的,無論這些數據庫連接是否被使用,連接池都將一直保證至少擁有這么多的連接數,當應用程序向連接池請求的連接數超過最大連接數量時,這些請求將被加入到等待隊列中.
數據庫連接池的最小連接數和最大連接數的設置要考慮到下列幾個因素:
1.最小連接數是連接池一直保持的數據庫連接,所以如果應用程序對數據庫連接的使用量不大,將會有大量的數據庫連接資源被浪費.
2.最大連接數是連接池申請的最大連接數,如果數據庫連接請求超過次數,后面的數據庫連接請求將被加入到等待對了中,這回影響之后的數據庫操作
如果最小連接數與最大連接數相差太大,那么最先的連接請求將會獲利,之后超過最小連接數量的連接請求等價於建立一個新的數據庫連接,不過,這些小於最小連接數的數據庫連接在使用完不會馬上被釋放,它將被放到連接池中等待重復使用或是空閑超時被釋放.
實例使用的Tomcat版本為6.0
方法一: 在Tomcat的conf/context.xml中配置
在Tomcat\apache-tomcat-6.0.33\conf目錄下的context.xml文件中配置默認值如下:
<?xml version='1.0' encoding='utf-8'?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> </Context>
配置連接池:
<?xml version='1.0' encoding='utf-8'?>
<Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <!--配置oracle數據庫的連接池--> <Resource name="jdbc/oracleds" author="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="scott" password="tiger" driverClassName="oracle.jdbc.dirver.OracleDriver" url="jdbc:oracle:thin:@127.0.0.1:1521:ora9" /> <!--配置mysql數據庫的連接池, 需要做的額外步驟是將mysql的Java驅動類放到tomcat的lib目錄下 maxIdle 連接池中最多可空閑maxIdle個連接 minIdle 連接池中最少空閑maxIdle個連接 initialSize 初始化連接數目 maxWait 連接池中連接用完時,新的請求等待時間,毫秒 username 數據庫用戶名 password 數據庫密碼 --> <Resource name="jdbc/mysqlds" auth="Container" type="javax.sql.DataSource" username="root" password="root" maxIdle="30" maxWait="10000" maxActive="100" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/db_blog" /> </Context>
配置好后需要注意的兩個步驟
1.將對應數據庫的驅動類放到tomcat的lib目錄西安
2.重新啟動tomcat服務器,讓配置生效
在web應用程序的web.xml中設置數據源參考,如下:
在<web-app></web-app>節點中加入下面內容
<resource-ref>
<description>mysql數據庫連接池</description> <!-- 參考數據源名字,同Tomcat中配置的Resource節點中name屬性值"jdbc/mysqlds"一致 --> <res-ref-name>jdbc/mysqlds</res-ref-name> <!-- 資源類型 --> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref>
錯誤解決:
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325) at javax.naming.InitialContext.lookup(InitialContext.java:392) at com.iblog.util.DBPoolUtil.<clinit>(DBPoolUtil.java:34)
解決方案:
上面的異常信息是配置文件中JNDI沒有初始化造成的
如果下面的問題都不存在
1.要去檢查下配置文件中連接數據庫的URL參數是否正確2.以及是否導入了正常的包3.檢查在Tomcat中conf/server.xml文件,檢查是否設置useNaming="false",如果是,去掉
2.那就是通過main方法測試的,這個數據源不支持這樣的測試方法,程序要運行在Tomcat中才能找到相應的數據源.[我在測試時犯這樣的錯導致上面錯誤出現]
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ page import="java.sql.*" %> <%@ page import="javax.naming.*" %> <%@ page import="javax.sql.DataSource" %>
import="java.sql.*, javax.sql.*, javax.naming.* <html> <head> <title>Tomcat6.0 JNDI!</title> </head> <body> Tomcat連接池測試,獲取數據源 <br> <% try { //初始化查找命名空間 Context ctx = new InitialContext(); //參數java:/comp/env為固定路徑 Context envContext = (Context)ctx.lookup("java:/comp/env"); //參數jdbc/mysqlds為數據源和JNDI綁定的名字 DataSource ds = (DataSource)envContext.lookup("jdbc/mysqlds"); Connection conn = ds.getConnection(); conn.close(); out.println("<span style='color:red;'>JNDI測試成功<span>"); } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } %> </body> </html>
運行效果:
方法二:在Tomcat的conf/server.xml中配置
打開tomcat的conf/server.xml文件,找到<GlobalNamingResources></GlobalNamingResources>節點,默認的內容如下
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources>
在該節點中加入相關的池配置信息,如下
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> <!--配置mysql數據庫的連接池, 需要做的額外步驟是將mysql的Java驅動類放到tomcat的lib目錄下 --> <Resource name="jdbc/mysqlds" auth="Container" type="javax.sql.DataSource" username="root" password="root" maxIdle="30" maxWait="10000" maxActive="100" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/db_blog" /> </GlobalNamingResources>
在tomcat的conf/context.xml文件中的<Context></Context>節點中加入如下內容
<ResourceLink name="jdbc/mysqlds" global="jdbc/mysqlds" type="javax.sql.DataSource"/>
然后在web項目中的WEB-INF目錄下的web.xml中配置
<resource-ref>
<description>mysql數據庫連接池</description> <!-- 參考數據源名字,同Tomcat中配置的Resource節點中name屬性值"jdbc/mysqlds"一致 --> <res-ref-name>jdbc/mysqlds</res-ref-name> <!-- 資源類型 --> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref>
同樣配置好后,需要重新啟動服務器,讓配置生效.
方法三:在Tomcat的conf/server.xml中配置虛擬目錄時配置
在配置虛擬目錄時,也就是在配置conf下面的server.xml時,在context標簽內添加池配置.
在說該方法之前,先說一下,如何用tomcat配置虛擬目錄
在tomcat\conf下server.xml中找到
<Host name="localhost" appBase="webapPS" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> </Host>
在其中添加:
<Context path="/website" docBase="F:/myweb" reloadable="true"></Context>
注意:
docBase要改成你的項目目錄。
path為虛擬路徑,訪問時的路徑,注意:一定要加“/” debug建議設置為0
reloadable設置為true。
這樣重新啟動tomcat
實例中如下配置
<Context path="/website" docBase="D:/program files/Tomcat/apache-tomcat-6.0.33/webapps/iblog.war" reloadable="true"> </Context>
接下來添加池配置,如下
<!--配置虛擬目錄-->
<Context path="/website" docBase="D:/program files/Tomcat/apache-tomcat-6.0.33/webapps/iblog.war" reloadable="true"> <Resource name="jdbc/mysqlds" auth="Container" type="javax.sql.DataSource" username="root" password="root" maxIdle="30" maxWait="10000" maxActive="100" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/db_blog" /> </Context>
啟動服務器,測試,注意因為我們配置了path值為”/website”,所以訪問的路徑應該為website.如下圖:
方法四:在Web項目中的META-INF目錄下新建一個文件context.xml,寫入配置
注意:是META-INF目錄下,不是WEB-INF目錄下新建
<?xml version='1.0' encoding='utf-8'?>
<Context> <Resource name="jdbc/mysqlds" auth="Container" type="javax.sql.DataSource" username="root" password="root" maxIdle="30" maxWait="10000" maxActive="100" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/db_blog" logAbandoned="true" /> </Context>
然后在WEB-INF中新建web.xml文件,然后將下面內容復制,保存
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<display-name>test</display-name>
<welcome-file-list>
<welcome-file>test.jsp</welcome-file>
</welcome-file-list>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/mysqlds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource;
4.完成后,重啟tomcat服務器。
方法五
Tomcat7 新的數據庫連接池Tomcat jdbc pool介紹和配置
1.Tomcat 中直接使用的方法:全局的連接池
在conf/server.xml下的<GlobalNamingResources>節點里配置resource,例如:
- <Resource name="jdbc/ens"
- auth="Container"
- type="javax.sql.DataSource"
- factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
- testWhileIdle="true"
- testOnBorrow="true"
- testOnReturn="false"
- validationInterval="30000"
- timeBetweenEvictionRunsMillis="30000"
- maxActive="100"
- minIdle="10"
- maxWait="10000"
- initialSize="10"
- removeAbandonedTimeout="60"
- removeAbandoned="true"
- logAbandoned="true"
- minEvictableIdleTimeMillis="30000"
- jmxEnabled="true"
- jdbcInterceptors=
- "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
- username="root"
- password="123"
- driverClassName="com.mysql.jdbc.Driver"
- url="jdbc:mysql://localhost:3306/ens"/>
然后,在context.xml文件的<Context></Context>節點中添加如下配置:
- <ResourceLink global="jdbc/ens" name="jdbc/ens" type="javax.sql.DataSource"/>
global="jdbc/ens" 中的參數值("jdbc/ens")必須和上一段<Resource >配置中的name屬性的值保持一樣。name="jdbc/ens" 這個可以隨便取,但是在程序中調用的時候,就應該與name的值保持一致。到這里,連接池已經配置好啦。
用JSP測試一下:
- <%@ page language="java" pageEncoding="gbk"%>
- <%@page import="java.sql.Connection"%>
- <%@page import="javax.naming.Context"%>
- <%@page import="javax.naming.InitialContext"%>
- <%@page import="javax.sql.DataSource"%>
- <%@page import="java.sql.Statement"%>
- <%@page import="java.sql.ResultSet"%>
- <%
- //連接池的獲取
- Connection conn = null;
- DataSource ds = null;
- ResultSet rs =null;
- Statement stmt = null;
- Context initCtx = new InitialContext();
- ds =(DataSource)initCtx.lookup("java:comp/env/jdbc/ens");
- if(ds!=null){
- out.println("已經獲得DataSource!");
- out.println("<br>");
- conn = ds.getConnection();
- try{
- stmt = conn.createStatement();
- String sql ="select * from ens_area";
- rs = stmt.executeQuery(sql);
- out.println("以下是從數據庫中讀取出來的數據:<br>");
- while(rs.next()){
- out.println("<br>");
- out.println(rs.getString("area_name"));
- }
- }catch(Exception ex){
- ex.printStackTrace();
- }finally{
- conn.close();
- rs.close();
- stmt.close();
- }
- }
- %>
方法六
Tomcat7 新的數據庫連接池Tomcat jdbc pool
(1)dbcp 是單線程的,為了保證線程安全會鎖整個連接池
(2)dbcp 性能不佳
(3)dbcp 太復雜,超過 60 個類,發展滯后。
因此,通常J2EE中還會使用其它的高性能連接池,如 C3P0,還有阿里系的 druid 等。為此,Tomcat 從 7.0 開始引入一個新的模塊: Tomcat jdbc pool
tomcat jdbc pool 近乎兼容 dbcp ,性能更高
異步方式獲取連接
tomcat jdbc pool 是 tomcat 的一個模塊,基於 tomcat JULI,使用 Tomcat 的日志框架
使用 javax.sql.PooledConnection 接口獲取連接
支持高並發應用環境
超簡單,核心文件只有8個,比 c3p0 還少
更好的空閑連接處理機制
支持 JMX
支持 XA Connection。
tomcat jdbc pool 可在 Tomcat 中直接使用,也可以在獨立的應用中使用。
在META-INF/context.xml下的<Context></Context>節點里配置resource,例如:
- <Resource name="j<span style="font-size:12px; line-height:1.45; white-space:pre-wrap">dbc/TestDB</span>"
- auth="Container"
- type="javax.sql.DataSource"
- factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
- testWhileIdle="true"
- testOnBorrow="true"
- testOnReturn="false"
- validationInterval="30000"
- timeBetweenEvictionRunsMillis="30000"
- maxActive="100"
- minIdle="10"
- maxWait="10000"
- initialSize="10"
- removeAbandonedTimeout="60"
- removeAbandoned="true"
- logAbandoned="true"
- minEvictableIdleTimeMillis="30000"
- jmxEnabled="true"
- jdbcInterceptors=
- "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
- username="root"
- password="123"
- driverClassName="com.mysql.jdbc.Driver"
- url="jdbc:mysql://localhost:3306/ens"/>
然后,在WEB-INF/web.xml文件的節點中添加如下配置:
- </resource-ref>
- <resource-ref>
- <description>DB_Connection</description>
- <res-ref-name>jdbc/TestDB</res-ref-name>
- <res-type>javax.sql.DataSource</res-type>
- <res-auth>Container</res-auth>
- </resource-ref>
這個可以隨便取,但是在程序中調用的時候,就應該與name的值保持一致。到這里,連接池已經配置好啦。
方法七為單個web項目配置數據池
1 配置連接池
將以下內容保存為context.xml,放在web項目下的META-INF文件夾下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE xml>
- <Context>
- <Resource name="jdbc/test"
- auth="Container"
- type="javax.sql.DataSource"
- factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
- maxActive="100" //最大激活連接
- maxIdle="30" //最大空閑連接
- maxWait="1000" //最大等待數
- username="test" //數據庫用戶名
- password="testtest" //數據庫密碼
- driverClassName="com.mysql.jdbc.Driver" //此處使用mysql數據庫,請自行修改驅動
- url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8" /> //test為數據庫名,編碼為UTF-8
- </Context>
2.項目中web.xml中引用連接池
<description>DB_Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
3 代碼中引用連接池
- package com.hrb2c.servlet;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.sql.Connection;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.util.concurrent.Future;
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import javax.naming.NamingException;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.tomcat.jdbc.pool.DataSource;
- /**
- * 數據庫連接池
- *
- * @author Yuedong Li
- *
- */
- @WebServlet("/ConnPoolTest")
- public class ConnPoolTest extends HttpServlet {
- private static final long serialVersionUID = 1L;
- private Connection con = null;
- private static DataSource datasource;
- /**
- * @see HttpServlet#HttpServlet()
- */
- public ConnPoolTest() {
- super();
- try {
- //獲取數據源
- datasource = getInstance();
- //連接池同步
- Future<Connection> future = datasource.getConnectionAsync();
- while (!future.isDone()) {
- // 等待連接池同步
- Thread.sleep(100);
- }
- // 獲取連接池
- con = future.get();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 單例模式獲取數據源
- * @return
- * @throws NamingException
- */
- private DataSource getInstance() throws NamingException {
- if (datasource == null) {
- Context initContext = new InitialContext();
- Context envContext = (Context) initContext.lookup("java:/comp/env");
- datasource = (DataSource) envContext.lookup("jdbc/test");
- }
- return datasource;
- }
- /**
- * 處理get方法
- */
- protected void doGet(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
- doPost(request, response);
- }
- /**
- * 處理post方法
- */
- protected void doPost(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
- Statement st;
- StringBuffer buff = new StringBuffer("<html><body>");
- try {
- if (con != null) {
- //簡單查詢,test表中有2列,id與name
- buff.append("id");
- buff.append(" ");
- buff.append("name");
- buff.append("<br>");
- st = con.createStatement();
- ResultSet rs = st.executeQuery("select * from test");
- while (rs.next()) {
- buff.append(rs.getString("id"));
- buff.append(" ");
- buff.append(rs.getString("name"));
- buff.append("<br>");
- }
- }
- buff.append("</body></html>");
- } catch (SQLException e) {
- e.printStackTrace();
- }
- PrintWriter out = response.getWriter();
- out.write(buff.toString());
- }
- }