用戶每次請求都須要向數據庫得到連接,而數據庫建立鏈接一般須要消耗相對較大的資源,建立時間也較長。假設網站一天10萬訪問量,數據庫服務器就須要建立10萬次鏈接,極大的浪費數據庫的資源,而且極易形成數據庫服務器內存溢出、拓機。以下圖所示:java
數據庫鏈接是一種關鍵的有限的昂貴的資源,這一點在多用戶的網頁應用程序中體現的尤其突出.對數據庫鏈接的管理能顯著影響到整個應用程序的伸縮性和健壯性,影響到程序的性能指標.數據庫鏈接池正式針對這個問題提出來的.數據庫鏈接池負責分配,管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而不是從新創建一個。以下圖所示:mysql
數據庫鏈接池在初始化時將建立必定數量的數據庫鏈接放到鏈接池中, 這些數據庫鏈接的數量是由最小數據庫鏈接數來設定的.不管這些數據庫鏈接是否被使用,鏈接池都將一直保證至少擁有這麼多的鏈接數量.鏈接池的最大數據庫鏈接數量限定了這個鏈接池能佔有的最大鏈接數,當應用程序向鏈接池請求的鏈接數超過最大鏈接數量時,這些請求將被加入到等待隊列中.sql
數據庫鏈接池的最小鏈接數和最大鏈接數的設置要考慮到如下幾個因素:數據庫
編寫鏈接池需實現java.sql.DataSource接口。DataSource接口中定義了兩個重載的getConnection方法:apache
實現DataSource接口,並實現鏈接池功能的步驟:編程
數據庫鏈接池核心代碼tomcat
使用動態代理技術構建鏈接池中的connection服務器
1 proxyConn = (Connection) Proxy.newProxyInstance(this.getClass() 2 .getClassLoader(), conn.getClass().getInterfaces(), 3 new InvocationHandler() { 4 //此處爲內部類,當close方法被調用時將conn還回池中,其它方法直接執行 5 public Object invoke(Object proxy, Method method, 6 Object[] args) throws Throwable { 7 if (method.getName().equals("close")) { 8 pool.addLast(conn); 9 return null; 10 } 11 return method.invoke(conn, args); 12 } 13 });
數據庫鏈接池編寫範例:oracle
1 package me.gacl.demo; 2 3 import java.io.InputStream; 4 import java.io.PrintWriter; 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Proxy; 8 import java.sql.Connection; 9 import java.sql.DriverManager; 10 import java.sql.SQLException; 11 import java.util.LinkedList; 12 import java.util.Properties; 13 import javax.sql.DataSource; 14 15 /** 16 * @ClassName: JdbcPool 17 * @Description:編寫數據庫鏈接池 18 * @author: 孤傲蒼狼 19 * @date: 2014-9-30 下午11:07:23 20 * 21 */ 22 public class JdbcPool implements DataSource{ 23 24 /** 25 * @Field: listConnections 26 * 使用LinkedList集合來存放數據庫連接, 27 * 因爲要頻繁讀寫List集合,因此這裏使用LinkedList存儲數據庫鏈接比較合適 28 */ 29 private static LinkedList<Connection> listConnections = new LinkedList<Connection>(); 30 31 static{ 32 //在靜態代碼塊中加載db.properties數據庫配置文件 33 InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties"); 34 Properties prop = new Properties(); 35 try { 36 prop.load(in); 37 String driver = prop.getProperty("driver"); 38 String url = prop.getProperty("url"); 39 String username = prop.getProperty("username"); 40 String password = prop.getProperty("password"); 41 //數據庫鏈接池的初始化鏈接數大小 42 int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize")); 43 //加載數據庫驅動 44 Class.forName(driver); 45 for (int i = 0; i < jdbcPoolInitSize; i++) { 46 Connection conn = DriverManager.getConnection(url, username, password); 47 System.out.println("獲取到了連接" + conn); 48 //將獲取到的數據庫鏈接加入到listConnections集合中,listConnections集合此時就是一個存放了數據庫鏈接的鏈接池 49 listConnections.add(conn); 50 } 51 52 } catch (Exception e) { 53 throw new ExceptionInInitializerError(e); 54 } 55 } 56 57 @Override 58 public PrintWriter getLogWriter() throws SQLException { 59 // TODO Auto-generated method stub 60 return null; 61 } 62 63 @Override 64 public void setLogWriter(PrintWriter out) throws SQLException { 65 // TODO Auto-generated method stub 66 67 } 68 69 @Override 70 public void setLoginTimeout(int seconds) throws SQLException { 71 // TODO Auto-generated method stub 72 73 } 74 75 @Override 76 public int getLoginTimeout() throws SQLException { 77 // TODO Auto-generated method stub 78 return 0; 79 } 80 81 @Override 82 public <T> T unwrap(Class<T> iface) throws SQLException { 83 // TODO Auto-generated method stub 84 return null; 85 } 86 87 @Override 88 public boolean isWrapperFor(Class<?> iface) throws SQLException { 89 // TODO Auto-generated method stub 90 return false; 91 } 92 93 /* 獲取數據庫鏈接 94 * @see javax.sql.DataSource#getConnection() 95 */ 96 @Override 97 public Connection getConnection() throws SQLException { 98 //若是數據庫鏈接池中的鏈接對象的個數大於0 99 if (listConnections.size()>0) { 100 //從listConnections集合中獲取一個數據庫鏈接 101 final Connection conn = listConnections.removeFirst(); 102 System.out.println("listConnections數據庫鏈接池大小是" + listConnections.size()); 103 //返回Connection對象的代理對象 104 return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){ 105 @Override 106 public Object invoke(Object proxy, Method method, Object[] args) 107 throws Throwable { 108 if(!method.getName().equals("close")){ 109 return method.invoke(conn, args); 110 }else{ 111 //若是調用的是Connection對象的close方法,就把conn還給數據庫鏈接池 112 listConnections.add(conn); 113 System.out.println(conn + "被還給listConnections數據庫鏈接池了!!"); 114 System.out.println("listConnections數據庫鏈接池大小爲" + listConnections.size()); 115 return null; 116 } 117 } 118 }); 119 }else { 120 throw new RuntimeException("對不起,數據庫忙"); 121 } 122 } 123 124 @Override 125 public Connection getConnection(String username, String password) 126 throws SQLException { 127 return null; 128 } 129 }
db.properties配置文件以下:app
1 driver=com.mysql.jdbc.Driver 2 url=jdbc:mysql://localhost:3306/jdbcStudy 3 username=root 4 password=XDP 5 6 jdbcPoolInitSize=10
寫一個JdbcUtil測試數據庫鏈接池
1 package me.gacl.utils; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import me.gacl.demo.JdbcPool; 8 9 public class JdbcUtil { 10 11 /** 12 * @Field: pool 13 * 數據庫鏈接池 14 */ 15 private static JdbcPool pool = new JdbcPool(); 16 17 /** 18 * @Method: getConnection 19 * @Description: 從數據庫鏈接池中獲取數據庫鏈接對象 20 * @Anthor:孤傲蒼狼 21 * @return Connection數據庫鏈接對象 22 * @throws SQLException 23 */ 24 public static Connection getConnection() throws SQLException{ 25 return pool.getConnection(); 26 } 27 28 /** 29 * @Method: release 30 * @Description: 釋放資源, 31 * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象 32 * @Anthor:孤傲蒼狼 33 * 34 * @param conn 35 * @param st 36 * @param rs 37 */ 38 public static void release(Connection conn,Statement st,ResultSet rs){ 39 if(rs!=null){ 40 try{ 41 //關閉存儲查詢結果的ResultSet對象 42 rs.close(); 43 }catch (Exception e) { 44 e.printStackTrace(); 45 } 46 rs = null; 47 } 48 if(st!=null){ 49 try{ 50 //關閉負責執行SQL命令的Statement對象 51 st.close(); 52 }catch (Exception e) { 53 e.printStackTrace(); 54 } 55 } 56 57 if(conn!=null){ 58 try{ 59 //關閉Connection數據庫鏈接對象 60 conn.close(); 61 }catch (Exception e) { 62 e.printStackTrace(); 63 } 64 } 65 } 66 }
如今不少WEB服務器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的實現,即鏈接池的實現。一般咱們把DataSource的實現,按其英文含義稱之爲數據源,數據源中都包含了數據庫鏈接池的實現。
也有一些開源組織提供了數據源的獨立實現:
在使用了數據庫鏈接池以後,在項目的實際開發中就不須要編寫鏈接數據庫的代碼了,直接從數據源得到數據庫的鏈接。
DBCP 是 Apache 軟件基金組織下的開源鏈接池實現,要使用DBCP數據源,須要應用程序應在系統中增長以下兩個 jar 文件:
Tomcat 的鏈接池正是採用該鏈接池來實現的。該數據庫鏈接池既能夠與應用服務器整合使用,也可由應用程序獨立使用。
1.導入相關jar包
commons-dbcp-1.2.2.jar、commons-pool.jar
二、在類目錄下加入dbcp的配置文件:dbcpconfig.properties
dbcpconfig.properties的配置信息以下:
1 #鏈接設置 2 driverClassName=com.mysql.jdbc.Driver 3 url=jdbc:mysql://localhost:3306/jdbcstudy 4 username=root 5 password=XDP 6 7 #<!-- 初始化鏈接 --> 8 initialSize=10 9 10 #最大鏈接數量 11 maxActive=50 12 13 #<!-- 最大空閒鏈接 --> 14 maxIdle=20 15 16 #<!-- 最小空閒鏈接 --> 17 minIdle=5 18 19 #<!-- 超時等待時間以毫秒爲單位 6000毫秒/1000等於60秒 --> 20 maxWait=60000 21 22 23 #JDBC驅動創建鏈接時附帶的鏈接屬性屬性的格式必須爲這樣:[屬性名=property;] 24 #注意:"user" 與 "password" 兩個屬性會被明確地傳遞,所以這裏不須要包含他們。 25 connectionProperties=useUnicode=true;characterEncoding=UTF8 26 27 #指定由鏈接池所建立的鏈接的自動提交(auto-commit)狀態。 28 defaultAutoCommit=true 29 30 #driver default 指定由鏈接池所建立的鏈接的只讀(read-only)狀態。 31 #若是沒有設置該值,則「setReadOnly」方法將不被調用。(某些驅動並不支持只讀模式,如:Informix) 32 defaultReadOnly= 33 34 #driver default 指定由鏈接池所建立的鏈接的事務級別(TransactionIsolation)。 35 #可用值爲下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE 36 defaultTransactionIsolation=READ_UNCOMMITTED
以下圖所示:
三、在獲取數據庫鏈接的工具類(如jdbcUtils)的靜態代碼塊中建立池
1 package me.gacl.util; 2 3 import java.io.InputStream; 4 import java.sql.Connection; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 import java.util.Properties; 9 import javax.sql.DataSource; 10 import org.apache.commons.dbcp.BasicDataSourceFactory; 11 12 /** 13 * @ClassName: JdbcUtils_DBCP 14 * @Description: 數據庫鏈接工具類 15 * @author: 孤傲蒼狼 16 * @date: 2014-10-4 下午6:04:36 17 * 18 */ 19 public class JdbcUtils_DBCP { 20 /** 21 * 在java中,編寫數據庫鏈接池需實現java.sql.DataSource接口,每一種數據庫鏈接池都是DataSource接口的實現 22 * DBCP鏈接池就是java.sql.DataSource接口的一個具體實現 23 */ 24 private static DataSource ds = null; 25 //在靜態代碼塊中建立數據庫鏈接池 26 static{ 27 try{ 28 //加載dbcpconfig.properties配置文件 29 InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); 30 Properties prop = new Properties(); 31 prop.load(in); 32 //建立數據源 33 ds = BasicDataSourceFactory.createDataSource(prop); 34 }catch (Exception e) { 35 throw new ExceptionInInitializerError(e); 36 } 37 } 38 39 /** 40 * @Method: getConnection 41 * @Description: 從數據源中獲取數據庫鏈接 42 * @Anthor:孤傲蒼狼 43 * @return Connection 44 * @throws SQLException 45 */ 46 public static Connection getConnection() throws SQLException{ 47 //從數據源中獲取數據庫鏈接 48 return ds.getConnection(); 49 } 50 51 /** 52 * @Method: release 53 * @Description: 釋放資源, 54 * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象 55 * @Anthor:孤傲蒼狼 56 * 57 * @param conn 58 * @param st 59 * @param rs 60 */ 61 public static void release(Connection conn,Statement st,ResultSet rs){ 62 if(rs!=null){ 63 try{ 64 //關閉存儲查詢結果的ResultSet對象 65 rs.close(); 66 }catch (Exception e) { 67 e.printStackTrace(); 68 } 69 rs = null; 70 } 71 if(st!=null){ 72 try{ 73 //關閉負責執行SQL命令的Statement對象 74 st.close(); 75 }catch (Exception e) { 76 e.printStackTrace(); 77 } 78 } 79 80 if(conn!=null){ 81 try{ 82 //將Connection鏈接對象還給數據庫鏈接池 83 conn.close(); 84 }catch (Exception e) { 85 e.printStackTrace(); 86 } 87 } 88 } 89 }
測試DBCP數據源
1 package me.gacl.test; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import org.junit.Test; 7 import me.gacl.util.JdbcUtils_DBCP; 8 9 public class DataSourceTest { 10 11 @Test 12 public void dbcpDataSourceTest() { 13 Connection conn = null; 14 PreparedStatement st = null; 15 ResultSet rs = null; 16 try{ 17 //獲取數據庫鏈接 18 conn = JdbcUtils_DBCP.getConnection(); 19 String sql = "insert into test1(name) values(?)"; 20 st = conn.prepareStatement(sql); 21 st.setString(1, "gacl"); 22 st.executeUpdate(); 23 //獲取數據庫自動生成的主鍵 24 rs = st.getGeneratedKeys(); 25 if(rs.next()){ 26 System.out.println(rs.getInt(1)); 27 } 28 }catch (Exception e) { 29 e.printStackTrace(); 30 }finally{ 31 //釋放資源 32 JdbcUtils_DBCP.release(conn, st, rs); 33 } 34 } 35 }
C3P0是一個開源的JDBC鏈接池,它實現了數據源和JNDI綁定,支持JDBC3規範和JDBC2的標準擴展。目前使用它的開源項目有Hibernate,Spring等。C3P0數據源在項目開發中使用得比較多。
c3p0與dbcp區別
1.導入相關jar包
c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar,若是操做的是Oracle數據庫,那麼還須要導入c3p0-oracle-thin-extras-0.9.2-pre1.jar
二、在類目錄下加入C3P0的配置文件:c3p0-config.xml
c3p0-config.xml的配置信息以下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- 3 c3p0-config.xml必須位於類路徑下面 4 private static ComboPooledDataSource ds; 5 static{ 6 try { 7 ds = new ComboPooledDataSource("MySQL"); 8 } catch (Exception e) { 9 throw new ExceptionInInitializerError(e); 10 } 11 } 12 --> 13 14 <c3p0-config> 15 <!-- 16 C3P0的缺省(默認)配置, 17 若是在代碼中「ComboPooledDataSource ds = new ComboPooledDataSource();」這樣寫就表示使用的是C3P0的缺省(默認)配置信息來建立數據源 18 --> 19 <default-config> 20 <property name="driverClass">com.mysql.jdbc.Driver</property> 21 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property> 22 <property name="user">root</property> 23 <property name="password">XDP</property> 24 25 <property name="acquireIncrement">5</property> 26 <property name="initialPoolSize">10</property> 27 <property name="minPoolSize">5</property> 28 <property name="maxPoolSize">20</property> 29 </default-config> 30 31 <!-- 32 C3P0的命名配置, 33 若是在代碼中「ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");」這樣寫就表示使用的是name是MySQL的配置信息來建立數據源 34 --> 35 <named-config name="MySQL"> 36 <property name="driverClass">com.mysql.jdbc.Driver</property> 37 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property> 38 <property name="user">root</property> 39 <property name="password">XDP</property> 40 41 <property name="acquireIncrement">5</property> 42 <property name="initialPoolSize">10</property> 43 <property name="minPoolSize">5</property> 44 <property name="maxPoolSize">20</property> 45 </named-config> 46 47 </c3p0-config>
以下圖所示:
三、在獲取數據庫鏈接的工具類(如jdbcUtils)的靜態代碼塊中建立池
1 package me.gacl.util; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import com.mchange.v2.c3p0.ComboPooledDataSource; 8 9 /** 10 * @ClassName: JdbcUtils_C3P0 11 * @Description: 數據庫鏈接工具類 12 * @author: 孤傲蒼狼 13 * @date: 2014-10-4 下午6:04:36 14 * 15 */ 16 public class JdbcUtils_C3P0 { 17 18 private static ComboPooledDataSource ds = null; 19 //在靜態代碼塊中建立數據庫鏈接池 20 static{ 21 try{ 22 //經過代碼建立C3P0數據庫鏈接池 23 /*ds = new ComboPooledDataSource(); 24 ds.setDriverClass("com.mysql.jdbc.Driver"); 25 ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy"); 26 ds.setUser("root"); 27 ds.setPassword("XDP"); 28 ds.setInitialPoolSize(10); 29 ds.setMinPoolSize(5); 30 ds.setMaxPoolSize(20);*/ 31 32 //經過讀取C3P0的xml配置文件建立數據源,C3P0的xml配置文件c3p0-config.xml必須放在src目錄下 33 //ds = new ComboPooledDataSource();//使用C3P0的默認配置來建立數據源 34 ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置來建立數據源 35 36 }catch (Exception e) { 37 throw new ExceptionInInitializerError(e); 38 } 39 } 40 41 /** 42 * @Method: getConnection 43 * @Description: 從數據源中獲取數據庫鏈接 44 * @Anthor:孤傲蒼狼 45 * @return Connection 46 * @throws SQLException 47 */ 48 public static Connection getConnection() throws SQLException{ 49 //從數據源中獲取數據庫鏈接 50 return ds.getConnection(); 51 } 52 53 /** 54 * @Method: release 55 * @Description: 釋放資源, 56 * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象 57 * @Anthor:孤傲蒼狼 58 * 59 * @param conn 60 * @param st 61 * @param rs 62 */ 63 public static void release(Connection conn,Statement st,ResultSet rs){ 64 if(rs!=null){ 65 try{ 66 //關閉存儲查詢結果的ResultSet對象 67 rs.close(); 68 }catch (Exception e) { 69 e.printStackTrace(); 70 } 71 rs = null; 72 } 73 if(st!=null){ 74 try{ 75 //關閉負責執行SQL命令的Statement對象 76 st.close(); 77 }catch (Exception e) { 78 e.printStackTrace(); 79 } 80 } 81 82 if(conn!=null){ 83 try{ 84 //將Connection鏈接對象還給數據庫鏈接池 85 conn.close(); 86 }catch (Exception e) { 87 e.printStackTrace(); 88 } 89 } 90 } 91 }
測試C3P0數據源
1 package me.gacl.test; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import org.junit.Test; 7 import me.gacl.util.JdbcUtils_C3P0; 8 import me.gacl.util.JdbcUtils_DBCP; 9 10 public class DataSourceTest { 11 12 @Test 13 public void c3p0DataSourceTest() { 14 Connection conn = null; 15 PreparedStatement st = null; 16 ResultSet rs = null; 17 try{ 18 //獲取數據庫鏈接 19 conn = JdbcUtils_C3P0.getConnection(); 20 String sql = "insert into test1(name) values(?)"; 21 st = conn.prepareStatement(sql); 22 st.setString(1, "gacl"); 23 st.executeUpdate(); 24 //獲取數據庫自動生成的主鍵 25 rs = st.getGeneratedKeys(); 26 if(rs.next()){ 27 System.out.println(rs.getInt(1)); 28 } 29 }catch (Exception e) { 30 e.printStackTrace(); 31 }finally{ 32 //釋放資源 33 JdbcUtils_C3P0.release(conn, st, rs); 34 } 35 } 36 }
在實際開發中,咱們有時候還會使用服務器提供給咱們的數據庫鏈接池,好比咱們但願Tomcat服務器在啓動的時候能夠幫咱們建立一個數據庫鏈接池,那麼咱們在應用程序中就不須要手動去建立數據庫鏈接池,直接使用Tomcat服務器建立好的數據庫鏈接池便可。要想讓Tomcat服務器在啓動的時候幫咱們建立一個數據庫鏈接池,那麼須要簡單配置一下Tomcat服務器。
JNDI(Java Naming and Directory Interface),Java命名和目錄接口,它對應於J2SE中的javax.naming包,
這 套API的主要做用在於:它能夠把Java對象放在一個容器中(JNDI容器),併爲容器中的java對象取一個名稱,之後程序想得到Java對象,只需 經過名稱檢索便可。其核心API爲Context,它表明JNDI容器,其lookup方法爲檢索容器中對應名稱的對象。
Tomcat服務器建立的數據源是以JNDI資源的形式發佈的,因此說在Tomat服務器中配置一個數據源實際上就是在配置一個JNDI資源,經過查看Tomcat文檔,咱們知道使用以下的方式配置tomcat服務器的數據源:
1 <Context> 2 <Resource name="jdbc/datasource" auth="Container" 3 type="javax.sql.DataSource" username="root" password="XDP" 4 driverClassName="com.mysql.jdbc.Driver" 5 url="jdbc:mysql://localhost:3306/jdbcstudy" 6 maxActive="8" maxIdle="4"/> 7 </Context>
服務器建立好數據源以後,咱們的應用程序又該怎麼樣獲得這個數據源呢,Tomcat服務器建立好數據源以後是以JNDI的形式綁定到一個JNDI容器中的,咱們能夠把JNDI想象成一個大大的容器,咱們能夠往這個容器中存放一些對象,一些資源,JNDI容器中存放的對象和資源都會有一個獨一無二的名稱,應用程序想從JNDI容器中獲取資源時,只須要告訴JNDI容器要獲取的資源的名稱,JNDI根據名稱去找到對應的資源後返回給應用程序。咱們平時作javaEE開發時,服務器會爲咱們的應用程序建立不少資源,好比request對象,response對象,服務器建立的這些資源有兩種方式提供給咱們的應用程序使用:第一種是經過方法參數的形式傳遞進來,好比咱們在Servlet中寫的doPost和doGet方法中使用到的request對象和response對象就是服務器以參數的形式傳遞給咱們的。第二種就是JNDI的方式,服務器把建立好的資源綁定到JNDI容器中去,應用程序想要使用資源時,就直接從JNDI容器中獲取相應的資源便可。
對於上面的name="jdbc/datasource"數據源資源,在應用程序中能夠用以下的代碼去獲取
1 Context initCtx = new InitialContext(); 2 Context envCtx = (Context) initCtx.lookup("java:comp/env"); 3 dataSource = (DataSource)envCtx.lookup("jdbc/datasource");
此種配置下,數據庫的驅動jar文件需放置在tomcat的lib下
一、在Web項目的WebRoot目錄下的META-INF目錄建立一個context.xml文件
以下圖所示:
二、在context.xml文件配置tomcat服務器的數據源
1 <Context> 2 <Resource 3 name="jdbc/datasource" 4 auth="Container" 5 type="javax.sql.DataSource" 6 username="root" 7 password="XDP" 8 driverClassName="com.mysql.jdbc.Driver" 9 url="jdbc:mysql://localhost:3306/jdbcstudy" 10 maxActive="8" 11 maxIdle="4"/> 12 </Context>
三、將數據庫的驅動jar文件需放置在tomcat的lib下
四、在獲取數據庫鏈接的工具類(如jdbcUtils)的靜態代碼塊中獲取JNDI容器中的數據源
1 package me.gacl.util; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import javax.naming.Context; 8 import javax.naming.InitialContext; 9 import javax.sql.DataSource; 10 11 /** 12 * @ClassName: JdbcUtils_DBCP 13 * @Description: 數據庫鏈接工具類 14 * @author: 孤傲蒼狼 15 * @date: 2014-10-4 下午6:04:36 16 * 17 */ 18 public class JdbcUtils_JNDI { 19 20 private static DataSource ds = null; 21 //在靜態代碼塊中建立數據庫鏈接池 22 static{ 23 try{ 24 //初始化JNDI 25 Context initCtx = new InitialContext(); 26 //獲得JNDI容器 27 Context envCtx = (Context) initCtx.lookup("java:comp/env"); 28 //從JNDI容器中檢索name爲jdbc/datasource的數據源 29 ds = (DataSource)envCtx.lookup("jdbc/datasource"); 30 }catch (Exception e) { 31 throw new ExceptionInInitializerError(e); 32 } 33 } 34 35 /** 36 * @Method: getConnection 37 * @Description: 從數據源中獲取數據庫鏈接 38 * @Anthor:孤傲蒼狼 39 * @return Connection 40 * @throws SQLException 41 */ 42 public static Connection getConnection() throws SQLException{ 43 //從數據源中獲取數據庫鏈接 44 return ds.getConnection(); 45 } 46 47 /** 48 * @Method: release 49 * @Description: 釋放資源, 50 * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象 51 * @Anthor:孤傲蒼狼 52 * 53 * @param conn 54 * @param st 55 * @param rs 56 */ 57 public static void release(Connection conn,Statement st,ResultSet rs){ 58 if(rs!=null){ 59 try{ 60 //關閉存儲查詢結果的ResultSet對象 61 rs.close(); 62 }catch (Exception e) { 63 e.printStackTrace(); 64 } 65 rs = null; 66 } 67 if(st!=null){ 68 try{ 69 //關閉負責執行SQL命令的Statement對象 70 st.close(); 71 }catch (Exception e) { 72 e.printStackTrace(); 73 } 74 } 75 76 if(conn!=null){ 77 try{ 78 //將Connection鏈接對象還給數據庫鏈接池 79 conn.close(); 80 }catch (Exception e) { 81 e.printStackTrace(); 82 } 83 } 84 } 85 }
寫一個Servlet測試JNDI數據源
1 package me.gacl.test; 2 3 import java.io.IOException; 4 import java.sql.Connection; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 import me.gacl.util.JdbcUtils_JNDI; 12 13 public class JNDITest extends HttpServlet { 14 15 public void doGet(HttpServletRequest request, HttpServletResponse response) 16 throws ServletException, IOException { 17 Connection conn = null; 18 PreparedStatement st = null; 19 ResultSet rs = null; 20 try{ 21 //獲取數據庫鏈接 22 conn = JdbcUtils_JNDI.getConnection(); 23 String sql = "insert into test1(name) values(?)"; 24 st = conn.prepareStatement(sql); 25 st.setString(1, "gacl"); 26 st.executeUpdate(); 27 //獲取數據庫自動生成的主鍵 28 rs = st.getGeneratedKeys(); 29 if(rs.next()){ 30 System.out.println(rs.getInt(1)); 31 } 32 }catch (Exception e) { 33 e.printStackTrace(); 34 }finally{ 35 //釋放資源 36 JdbcUtils_JNDI.release(conn, st, rs); 37 } 38 } 39 40 public void doPost(HttpServletRequest request, HttpServletResponse response) 41 throws ServletException, IOException { 42 doGet(request, response); 43 } 44 45 }