詳細介紹數據庫連接池c3p0、dbcp和dbutils工具類


詳細介紹c3p0、dbcp數據庫連接池的使用,簡單介紹和應用dbutils工具類


一、數據庫連接池的簡單介紹

1.數據庫連接池簡介

在系統初始化時,將數據庫連接作為對象存儲在內存中,當用戶需要訪問數據庫時,並非建立一個新連接,而是從連接池中取出一個已建立的空閑連接對象。

使用完畢后,用戶也並非將連接關閉,而是將連接放回連接池中,以供下一個請求訪問使用。

而連接的建立、斷開都由連接池自身來管理。同時,還可以通過設置連接池的參數來控制連接池中的初始連接數、連接的上下限數以及每個連接的最大使用次數、最大空閑時間等等。也可以通過其自身的管理機制來監視數據庫連接的數量、使用情況。
數據庫連接池工作原理



2.數據庫連接池原理簡介

數據庫連接池的基本原理就是為數據庫建立一個緩沖池。在緩沖池中先創建指定數量的數據庫連接,當有連接請求時就從緩沖池中取出 處於空閑狀態的連接,並將此連接標記為忙碌。知道該請求進程結束后,它所使用的連接才會重新回到空閑狀態,並等待下一次請求調用。

所以綜上所述,數據庫連接池的主要作用就是負責分配、管理和釋放數據庫連接,它允許程序重復使用同一個現有的數據庫連接,大大縮短了運行時間,提高了執行效率。



3.使用數據庫連接池的必要性

當我們在進行基於數據庫的web程序開發時,我們可以現在主程序中通過JDBC的DriverManager建立數據庫連接,然后將要對數據庫進行操作的sql語句封裝到Statement中,最后在返回結果集后斷開數據庫連接。這種較為傳統的開發模式很容易造成安全隱患。

因為每一個數據庫連接使用完后都需要斷開連接,但如果程序出現異常導致 連接未能及時關閉,這樣就可能導致內存泄漏;另外使用傳統JDBC模式開發不能控制需要創建的連接數,系統一般會將資源大量分出給連接以防止資源不夠用,但是如果連接數超出一定數量也會有極大可能造成內存泄漏問題

普通的JDBC數據庫連接使用DriverManager來獲取,每次向數據庫簡歷連接的時候都要將Connection加載到內存中,再根據JDBC代碼(或配置文件)中用戶名和密碼進行驗證。由此可見,如果同一個數據庫在同一時間數十人甚至上百人請求連接勢必會占用大量系統資源,嚴重會導致服務器崩潰




二、c3p0數據庫連接池的使用

1.定義

c3p0是一個開源的JDBC連接池,它實現了數據源與JDNDI綁定,支持JDBC3規范和實現了JDBC2的擴展 說明的Connection和Statement池的DataSource對象。

即將用於連接數據庫的連接整合在一起行程一個隨取隨用的數據庫連接池(Connection pool)



2.使用

- 導入jar包:c3p0的jar包和musq驅動jar包


- 配置配置文件(兩種方式取一,放在src路徑下)

c3p0-config.xml

<c3p0-config>   
 <default-config>   
 <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->   
 <property name="acquireIncrement">3</property>   

 <!--定義在從數據庫獲取新連接失敗后重復嘗試的次數。Default: 30 -->   
 <property name="acquireRetryAttempts">30</property>   
    
 <!--兩次連接中間隔時間,單位毫秒。Default: 1000 -->   
 <property name="acquireRetryDelay">1000</property>   
    
 <!--連接關閉時默認將所有未提交的操作回滾。Default: false -->   
 <property name="autoCommitOnClose">false</property>   
    
 <!--c3p0將建一張名為Test的空表,並使用其自帶的查詢語句進行測試。如果定義了這個參數那么   
 屬性preferredTestQuery將被忽略。你不能在這張Test表上進行任何操作,它將只供c3p0測試   
 使用。Default: null-->   
 <property name="automaticTestTable">Test</property>   
    
 <!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效   
 保留,並在下次調用getConnection()的時候繼續嘗試獲取連接。如果設為true,那么在嘗試   
 獲取連接失敗后該數據源將申明已斷開並永久關閉。Default: false-->   
 <property name="breakAfterAcquireFailure">false</property>   
    
 <!--當連接池用完時客戶端調用getConnection()后等待獲取新連接的時間,超時后將拋出   
 SQLException,如設為0則無限期等待。單位毫秒。Default: 0 -->   
 <property name="checkoutTimeout">100</property>   
    
 <!--通過實現ConnectionTester或QueryConnectionTester的類來測試連接。類名需制定全路徑。   
 Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->   
 <property name="connectionTesterClassName"></property>   
    
 <!--指定c3p0 libraries的路徑,如果(通常都是這樣)在本地即可獲得那么無需設置,默認null即可   
 Default: null-->   
 <property name="factoryClassLocation">null</property>   
    
 <!--強烈不建議使用該方法,將這個設置為true可能會導致一些微妙而奇怪的bug-->   
 <property name="forceIgnoreUnresolvedTransactions">false</property>   
    
 <!--每60秒檢查所有連接池中的空閑連接。Default: 0 -->   
 <property name="idleConnectionTestPeriod">60</property>   
    
 <!--初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間。Default: 3 -->   
 <property name="initialPoolSize">3</property>   
    
 <!--最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->   
 <property name="maxIdleTime">60</property>   
    
 <!--連接池中保留的最大連接數。Default: 15 -->   
 <property name="maxPoolSize">15</property>   
    
 <!--JDBC的標准參數,用以控制數據源內加載的PreparedStatements數量。但由於預緩存的statements   
 屬於單個connection而不是整個連接池。所以設置這個參數需要考慮到多方面的因素。   
 如果maxStatements與maxStatementsPerConnection均為0,則緩存被關閉。Default: 0-->   
 <property name="maxStatements">100</property>   
    
 <!--maxStatementsPerConnection定義了連接池內單個連接所擁有的最大緩存statements數。Default: 0 -->   
 <property name="maxStatementsPerConnection"></property>   
    
 <!--c3p0是異步操作的,緩慢的JDBC操作通過幫助進程完成。擴展這些操作可以有效的提升性能   
 通過多線程實現多個操作同時被執行。Default: 3-->   
 <property name="numHelperThreads">3</property>   
    
 <!--當用戶調用getConnection()時使root用戶成為去獲取連接的用戶。主要用於連接池連接非c3p0   
 的數據源時。Default: null-->   
 <property name="overrideDefaultUser">root</property>   
    
 <!--與overrideDefaultUser參數對應使用的一個參數。Default: null-->   
 <property name="overrideDefaultPassword">password</property>   
    
 <!--密碼。Default: null-->   
 <property name="password"></property>   
    
 <!--定義所有連接測試都執行的測試語句。在使用連接測試的情況下這個一顯著提高測試速度。注意:   
 測試的表必須在初始數據源的時候就存在。Default: null-->   
 <property name="preferredTestQuery">select id from test where id=1</property>   
    
 <!--用戶修改系統配置參數執行前最多等待300秒。Default: 300 -->   
 <property name="propertyCycle">300</property>   
    
 <!--因性能消耗大請只在需要的時候使用它。如果設為true那么在每個connection提交的   
 時候都將校驗其有效性。建議使用idleConnectionTestPeriod或automaticTestTable   
 等方法來提升連接測試的性能。Default: false -->   
 <property name="testConnectionOnCheckout">false</property>   
    
 <!--如果設為true那么在取得連接的同時將校驗連接的有效性。Default: false -->   
 <property name="testConnectionOnCheckin">true</property>   
    
 <!--用戶名。Default: null-->   
 <property name="user">root</property>   
    
 <!--早期的c3p0版本對JDBC接口采用動態反射代理。在早期版本用途廣泛的情況下這個參數   
 允許用戶恢復到動態反射代理以解決不穩定的故障。最新的非反射代理更快並且已經開始   
 廣泛的被使用,所以這個參數未必有用。現在原先的動態反射與新的非反射代理同時受到   
 支持,但今后可能的版本可能不支持動態反射代理。Default: false-->   
 <property name="usesTraditionalReflectiveProxies">false</property> 
 </default-config>      
</c3p0-config>

c3p0.properties

c3p0.driverClass = com.mysql.jdbc.Driver
c3p0.jdbcUrl = jdbc:mysql://localhost:3306/webexam
c3p0.user = root
c3p0.password =
c3p0.maxPoolSize = 20
c3p0.minPoolSize = 3
c3p0.maxStatements = 30
c3p0.maxIdleTime = 150

注:c3p0讀取配置優先級如下(優先級權重值從上到下)

  • Configuration values programmatically set. 【以編程方式設置配置值。】
  • System property setting of configuration value. 【配置值的系統屬性設置。】
  • Configuration values taken from the default configuration of a c3p0-config.xml file. 【配置值取自c3p0-config.xml文件的默認配置。】
  • Configuration values specified in a c3p0.properties file 【在c3p0.properties文件中指定的配置值】
  • c3p0's hard-coded default values. 【c3p0的硬編碼默認值。】
    由此可見,配置文件c3p0-config.xml是比c3p0.properties配置文件優先級高的,也是c3p0官方推薦的一種方式。

-c3p0工具類

public class C3P0Util {
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource("poolConnection");
	

	public static ComboPooledDataSource getDataSource(){
		return dataSource;
	}
	
	//從連接池中獲取連接
	public static Connection getConnection(){
		try {
			return (Connection) dataSource.getConnection();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	//將連接歸還連接池
	public static void release(Connection conn,Statement stmt,ResultSet rs){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			rs=null;
		}
		
		if(stmt!=null){
			try {
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			stmt=null;
		}
		
		if(conn!=null){
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			conn=null;
		}
	}
	
	
	public static void release(Connection conn,PreparedStatement ps,ResultSet rs){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			rs=null;
		}
		
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ps=null;
		}
		
		if(conn!=null){
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			conn=null;
		}
	}
	
	public static void release(Connection conn){
		if(conn!=null){
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			conn=null;
		}
	}
}



三、dbcp數據庫連接池的使用

1.定義

DBCP(database connection pool)是Apache軟件基金組織下的開源連接池實現,該連接池依賴該組織下的另一個開源系統:Common-pool



2.使用

- 導入jar包

commons-dbutils.jar
commons-pool.jar

- 配置文件

dbcp.properties

#連接設置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/student
username=root
password=666666
initialSize=10
maxActive=50
maxIdle=20
minIdle=5
maxWait=60000
connectionProperties=useUnicode=true;characterEncoding=utf8
defaultAutoCommit=true
defaultReadOnly=
defaultTransactionIsolation=REPEATABLE_READ

DBCPUtils工具類

public class DBCPUtils {
    static DataSource ds = null;
    static {
        try {
            // 得到配置文件
            Properties prop = new Properties();
            prop.load(DBCPUtils.class.getClassLoader().getResourceAsStream(
                    "dbcpconfig.properties"));
            // 根據配置文件創建數據庫連接池(數據源)
            ds = BasicDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            throw new ExceptionInInitializerError("DBCP初始化異常,請檢查配置文件!!!");
        }
    }

    /**
     * 得到數據庫連接對象
     * 
     * @return
     */
    public static Connection getConnection() {
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("服務器忙。。。");
        }
    }

    /**
     * 關閉所有資源連接
     * 
     * @param conn
     * @param ps
     * @param rs
     */
    public static void releaseAll(Connection conn, Statement ps, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            conn = null;
        }

        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ps = null;
        }

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            rs = null;
        }
    }
}



四、dbutils工具類的簡單應用

1.DBUtil核心功能

QueryRunner中提供對sql語句操作的API

ResultSetHandler接口,用於定義select操作后,怎樣封裝結果集

DBUtils類是一個工具類,定義了關閉資源與事務處理的方法



2.QueryRunner核心類

QueryRunner(DataSource ds) 傳入參數為連接池

update(String sql,Objec....params) 執行insert update delete操作

query(String sql ,ResultSetHandler rsh,Object....params) 執行 select操作

3.ResultSetHandler結果集處理類

ResultSetHandler常用方法



4.實例代碼

-關於增刪改查

/*
 *  使用QueryRunner類,實現對數據表的
 *  insert delete update
 *  調用QueryRunner類的方法 update (Connection con,String sql,Object...param)
 *  Object...param 可變參數,Object類型,SQL語句會出現?占位符
 *  數據庫連接對象,自定義的工具類傳遞
*/
public class QueryRunnerDemo {
	private static Connection con = JDBCUtilConfig.getConnection();
	
	public static void main(String[] args)throws SQLException {
		//insert();
		update();
		//delete();
	}
	/*
	 *  定義方法,使用QueryRunner類的方法delete將數據表的數據刪除
	 */
	public static void delete()throws SQLException{
		//創建QueryRunner類對象
		QueryRunner qr = new QueryRunner();	
		//寫刪除的SQL語句
		String sql = "DELETE FROM sort WHERE sid=?";
		//調用QueryRunner方法update
		int row = qr.update(con, sql, 8);
		System.out.println(row);
		/*
		 *  判斷insert,update,delete執行是否成功
		 *  對返回值row判斷
		 *  if(row>0) 執行成功
		 */
		DbUtils.closeQuietly(con);
	}
	
	/*
	 *  定義方法,使用QueryRunner類的方法update將數據表的數據修改
	 */
	public static void update()throws SQLException{
		//創建QueryRunner類對象
		QueryRunner qr = new QueryRunner();	
		//寫修改數據的SQL語句
		String sql = "UPDATE sort SET sname=?,sprice=?,sdesc=? WHERE sid=?";
		//定義Object數組,存儲?中的參數
		Object[] params = {"花卉",100.88,"情人節玫瑰花",4};
		//調用QueryRunner方法update
		int row = qr.update(con, sql, params);
		System.out.println(row);
		DbUtils.closeQuietly(con);
	}
	
	
	/*
	 * 定義方法,使用QueryRunner類的方法update向數據表中,添加數據
	 */
	public static void insert()throws SQLException{
		//創建QueryRunner類對象
		QueryRunner qr = new QueryRunner();
		String sql = "INSERT INTO sort (sname,sprice,sdesc)VALUES(?,?,?)";
		//將三個?占位符的實際參數,寫在數組中
		Object[] params = {"體育用品",289.32,"購買體育用品"};
		//調用QueryRunner類的方法update執行SQL語句
		int row = qr.update(con, sql, params);
		System.out.println(row);
		DbUtils.closeQuietly(con);
	}
}

-關於查詢

category.java

// JavaBean
public class Category {
	private String cid;
	private String cname;
	
	public String getCid() {
		return cid;
	}
	public void setCid(String cid) {
		this.cid = cid;
	}
	
	public String getCname() {
		return cname;
	}
	public void setCname(String cname) {
		this.cname = cname;
	}
	@Override
	public String toString() {
		return "Category [cid=" + cid + ", cname=" + cname + "]";
	}
	public Category() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Category(String cid, String cname) {
		super();
		this.cid = cid;
		this.cname = cname;
	}
}

C3P0Utils.java
/**
 * 在C3P0連接池中 遵循了javax.sql.DataSource接口的實現類:
 * 		ComboPooledDataSource
*/
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Utils {

	private static ComboPooledDataSource ds = new ComboPooledDataSource();	
	// 自動加載C3P0-config.xml文件

	public static DataSource getDataSource(){
		return ds;
	}
	
	public static Connection getConnection() throws SQLException{
		// 獲取連接,從C3P0連接池獲取
		return ds.getConnection();
	}
	
	// 關閉所有資源的統一代碼
	public static void closeAll(Connection conn, Statement st, ResultSet rs){
		//負責關閉
		if(conn != null){
			try {
				conn.close();		// 使用代理,放回到連接池中
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(st != null){
			try {
				st.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}	
}

DBUtils.java

package cn.simon.jdbc.demo03_DBUtils的使用;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import cn.simon.jdbc.domain.Category;

/**
 *  DBUtils執行數據庫查詢操作
 *  	1.QueryRunner(DataSource)
 *  	2.query(String sql, ResultSetHandler<T> rsh, Object... params); // 主要執行查詢
*/

public class DBUtilsDemo {
	public static void main(String[] args) throws SQLException {
		// TODO Auto-generated method stub

//		queryDemo01();
//		queryDemo02();
//		queryDemo03();
//		queryDemo04();
//		queryDemo05();
		queryDemo06();
//		queryDemo07();
//		queryDemo08();
	}
	
	// ArrayHandler處理類的使用
	public static void queryDemo01() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		Object[] objs = qr.query("select * from category where cid = ?", new ArrayHandler(), 1);
		for(Object o: objs){		// object[]中保存了object對象
			System.out.println(o);
		}
	}
	
	// ArrayListHandler
	public static void queryDemo02() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		List<Object[]> objs = qr.query("select * from category ", new ArrayListHandler());
		for (Object[] objects : objs) {
			System.out.println(objects[0]+"\t"+objects[1]);
		}
	}
	
	// BeanHandler處理類的使用
	public static void queryDemo03() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		String sql = "select * from category";
		Category c = qr.query(sql, new BeanHandler<Category>(Category.class));
		System.out.println(c);
	}
	
	// BeanListHandler
	public static void queryDemo04() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		String sql = "select * from category";
		List<Category> c = qr.query(sql, new BeanListHandler<Category>(Category.class));
		for (Category category : c) {
			System.out.println(category);
		}
	}
	
	// ColumnListHandler處理類的使用
	public static void queryDemo05() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		String sql = "select * from category";
		List<Object> c = qr.query(sql, new ColumnListHandler<Object>("cname"));
		System.out.println(c);
	}
	
	// MapHandler處理類的使用
	public static void queryDemo06() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		String sql = "select * from category";
		Map<String, Object> map = qr.query(sql, new MapHandler());
		// 3.
		System.out.println(map);
	}
	
	// MapListHandler處理類的使用
	public static void queryDemo07() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		String sql = "select * from category";
		List<Map<String, Object>> maps = qr.query(sql, new MapListHandler());
		// 3.List
		System.out.println(maps);
	}
	
	// MapListHandler處理類的使用
	public static void queryDemo08() throws SQLException{
		// 1.創建QueryRunner對象
		QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
		// 2.執行查詢
		String sql = "select count(*) from category";
		Long count = qr.query(sql, new ScalarHandler<Long>());
		// 3.List
		System.out.println(count);
	}
}



五、文章引用/參考

https://www.mchange.com/projects/c3p0/index.html
https://www.cnblogs.com/SUN99bk/p/12181493.html
https://www.cnblogs.com/ygj0930/p/6405861.html
https://www.cnblogs.com/xww0826/p/10359479.html#1、DBCP連接池
https://www.cnblogs.com/lztkdr/p/DBCPUtils.html
http://commons.apache.org/proper/commons-dbcp/configuration.html
https://www.jb51.net/article/101072.htm
https://www.cnblogs.com/sunseine/p/5947448.html
https://blog.csdn.net/simonforfuture/article/details/90480147
https://blog.csdn.net/a911711054/article/details/77719685?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase
https://blog.csdn.net/qq_25106373/article/details/80955184


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM