欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中幾種常用數(shù)據(jù)庫(kù)連接池的使用

 更新時(shí)間:2021年05月27日 11:00:38   作者:孤傲的小狼  
數(shù)據(jù)庫(kù)連接池在編寫應(yīng)用服務(wù)是經(jīng)常需要用到的模塊,太過(guò)頻繁的連接數(shù)據(jù)庫(kù)對(duì)服務(wù)性能來(lái)講是一個(gè)瓶頸,使用緩沖池技術(shù)可以來(lái)消除這個(gè)瓶頸,本文就來(lái)介紹Java常見(jiàn)的幾種,感興趣的可以了解一下

一、應(yīng)用程序直接獲取數(shù)據(jù)庫(kù)連接的缺點(diǎn)

  用戶每次請(qǐng)求都需要向數(shù)據(jù)庫(kù)獲得鏈接,而數(shù)據(jù)庫(kù)創(chuàng)建連接通常需要消耗相對(duì)較大的資源,創(chuàng)建時(shí)間也較長(zhǎng)。假設(shè)網(wǎng)站一天10萬(wàn)訪問(wèn)量,數(shù)據(jù)庫(kù)服務(wù)器就需要?jiǎng)?chuàng)建10萬(wàn)次連接,極大的浪費(fèi)數(shù)據(jù)庫(kù)的資源,并且極易造成數(shù)據(jù)庫(kù)服務(wù)器內(nèi)存溢出、拓機(jī)。如下圖所示:

二、使用數(shù)據(jù)庫(kù)連接池優(yōu)化程序性能

2.1、數(shù)據(jù)庫(kù)連接池的基本概念

  數(shù)據(jù)庫(kù)連接是一種關(guān)鍵的有限的昂貴的資源,這一點(diǎn)在多用戶的網(wǎng)頁(yè)應(yīng)用程序中體現(xiàn)的尤為突出.對(duì)數(shù)據(jù)庫(kù)連接的管理能顯著影響到整個(gè)應(yīng)用程序的伸縮性和健壯性,影響到程序的性能指標(biāo).數(shù)據(jù)庫(kù)連接池正式針對(duì)這個(gè)問(wèn)題提出來(lái)的.數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配,管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,而不是重新建立一個(gè)。如下圖所示:

       數(shù)據(jù)庫(kù)連接池在初始化時(shí)將創(chuàng)建一定數(shù)量的數(shù)據(jù)庫(kù)連接放到連接池中, 這些數(shù)據(jù)庫(kù)連接的數(shù)量是由最小數(shù)據(jù)庫(kù)連接數(shù)來(lái)設(shè)定的.無(wú)論這些數(shù)據(jù)庫(kù)連接是否被使用,連接池都將一直保證至少擁有這么多的連接數(shù)量.連接池的最大數(shù)據(jù)庫(kù)連接數(shù)量限定了這個(gè)連接池能占有的最大連接數(shù),當(dāng)應(yīng)用程序向連接池請(qǐng)求的連接數(shù)超過(guò)最大連接數(shù)量時(shí),這些請(qǐng)求將被加入到等待隊(duì)列中.

       數(shù)據(jù)庫(kù)連接池的最小連接數(shù)和最大連接數(shù)的設(shè)置要考慮到以下幾個(gè)因素:

  • 最小連接數(shù):是連接池一直保持的數(shù)據(jù)庫(kù)連接,所以如果應(yīng)用程序?qū)?shù)據(jù)庫(kù)連接的使用量不大,將會(huì)有大量的數(shù)據(jù)庫(kù)連接資源被浪費(fèi).
  • 最大連接數(shù):是連接池能申請(qǐng)的最大連接數(shù),如果數(shù)據(jù)庫(kù)連接請(qǐng)求超過(guò)次數(shù),后面的數(shù)據(jù)庫(kù)連接請(qǐng)求將被加入到等待隊(duì)列中,這會(huì)影響以后的數(shù)據(jù)庫(kù)操作
  • 如果最小連接數(shù)與最大連接數(shù)相差很大:那么最先連接請(qǐng)求將會(huì)獲利,之后超過(guò)最小連接數(shù)量的連接請(qǐng)求等價(jià)于建立一個(gè)新的數(shù)據(jù)庫(kù)連接.不過(guò),這些大于最小連接數(shù)的數(shù)據(jù)庫(kù)連接在使用完不會(huì)馬上被釋放,他將被放到連接池中等待重復(fù)使用或是空間超時(shí)后被釋放.

2.2、編寫數(shù)據(jù)庫(kù)連接池

  編寫連接池需實(shí)現(xiàn)java.sql.DataSource接口。DataSource接口中定義了兩個(gè)重載的getConnection方法:

  • Connection getConnection()
  • Connection getConnection(String username, String password)

  實(shí)現(xiàn)DataSource接口,并實(shí)現(xiàn)連接池功能的步驟:

  • 在DataSource構(gòu)造函數(shù)中批量創(chuàng)建與數(shù)據(jù)庫(kù)的連接,并把創(chuàng)建的連接加入LinkedList對(duì)象中。
  • 實(shí)現(xiàn)getConnection方法,讓getConnection方法每次調(diào)用時(shí),從LinkedList中取一個(gè)Connection返回給用戶。
  • 當(dāng)用戶使用完Connection,調(diào)用Connection.close()方法時(shí),Collection對(duì)象應(yīng)保證將自己返回到LinkedList中,而不要把conn還給數(shù)據(jù)庫(kù)。Collection保證將自己返回到LinkedList中是此處編程的難點(diǎn)。

 數(shù)據(jù)庫(kù)連接池核心代碼

  使用動(dòng)態(tài)代理技術(shù)構(gòu)建連接池中的connection

 JdbcPool.java:

大致思路:1、讀取配置文件,將屬性值取出

                   2、注冊(cè)jdbc驅(qū)動(dòng)

                   3、通過(guò)數(shù)據(jù)庫(kù)連接數(shù)和驅(qū)動(dòng)管理器獲得相應(yīng)連接(.getConnection()),因?yàn)镈ataSource是接口,所以這個(gè)方法需要                           我們手動(dòng)實(shí)現(xiàn)

                   4、重點(diǎn):實(shí)現(xiàn)getConnection()方法

                          思考:當(dāng)外部有連接需求時(shí),直接從connectList拿出一個(gè)connect,就實(shí)現(xiàn)了這個(gè)方法,但是我們?cè)傧胂耄猛炅嗽趺椿厥漳?,確實(shí),有close()方法,但是這個(gè)方法作用是將這個(gè)連接還給數(shù)據(jù)庫(kù),而不是數(shù)據(jù)庫(kù)連接池,這樣會(huì)導(dǎo)致數(shù)據(jù)庫(kù)連接池中 的連接越來(lái)越少,這樣可不行,但是我們也不能影響它的正常使用吧,在這種情況下,我們想要監(jiān)測(cè)這個(gè)連接對(duì)象的動(dòng)態(tài),在它調(diào)用close()方法時(shí),我們將其再添加進(jìn)connectList,這樣連接池中的連接不就沒(méi)少了嗎,在java中對(duì)于監(jiān)聽(tīng)一個(gè)對(duì)象的動(dòng)態(tài),最常用也最實(shí)用的便是動(dòng)態(tài)代理,對(duì)于動(dòng)態(tài)代理,其實(shí)我們可以把它想象成就是一個(gè)大盒子,里面裝著一個(gè)真實(shí)對(duì)象小盒子,這就在大盒子和小盒子間形成了一個(gè)橫切空隙,而真實(shí)做事的還是這個(gè)對(duì)象,代理只是個(gè)接活的,接到活就給內(nèi)部的小盒子干,自然這個(gè)空隙可以用來(lái)監(jiān)測(cè)真實(shí)對(duì)象的事務(wù),也就是監(jiān)聽(tīng)對(duì)象的方法。具體可以看看這個(gè),動(dòng)態(tài)代理:http://www.dbjr.com.cn/article/213416.htm

package jdbcPoolTest;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;
 
import javax.sql.DataSource;
 
import org.omg.PortableServer.POA;
 
public class JdbcPool implements DataSource{
	
	
	private static LinkedList<Connection> listConnections = new LinkedList<>();
	
	static {
		//靜態(tài)代碼塊中加載db.properties配置文件
		InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
		
		Properties prop = new Properties();
		try {
			//讀取文件內(nèi)容
			prop.load(in);
			String driver = prop.getProperty("driver");
			String url = prop.getProperty("url");
			String username = prop.getProperty("username");
			String password = prop.getProperty("password");
			
			//數(shù)據(jù)庫(kù)連接池的初始化連接大小
			int jdbcPoolInitSize = Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
			//加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)		
			Class.forName(driver);	
			for(int i=0; i<jdbcPoolInitSize; i++) {
			//獲取連接	
			Connection conn = DriverManager.getConnection(url, username, password);
			System.out.println("獲取連接:"+conn);
			//將conn連接加入listConnections集合中,此時(shí)的listConnections就是一個(gè)連接池
			listConnections.add(conn);
			
				
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
	}
 
	@Override
	public Connection getConnection() throws SQLException {
		// TODO Auto-generated method stub
		//如果數(shù)據(jù)庫(kù)連接池的連接數(shù)大于0
		System.out.println("進(jìn)來(lái)了");
		if (listConnections.size()>0) {
			//從listConnections中獲取一個(gè)連接
			final Connection conn = listConnections.removeFirst();
			System.out.println("數(shù)據(jù)庫(kù)連接池的大小為:"+listConnections.size());
			//返回Connection的代理,利用代理可以處理一些橫切事件
			System.out.println("取出的連接為:"+conn);
			return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() {
				
				@Override
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					// TODO Auto-generated method stub
					//如果不是執(zhí)行關(guān)閉操作,則通過(guò)反射執(zhí)行相應(yīng)方法
					if (!method.getName().equals("close")) {
												
						return method.invoke(conn, args);
						
					}else {
						//否則,將conn歸還給連接池
						listConnections.add(conn);
						System.out.println("歸還連接:"+conn);
						System.out.println("連接池大小為:"+listConnections.size());
						return null;
					}
					
				}
			});
			
		}else {
			throw new RuntimeException("對(duì)不起,數(shù)據(jù)庫(kù)正忙");
		}
		
	}
	@Override
	public PrintWriter getLogWriter() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}
 
	@Override
	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}
 
	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}
 
	@Override
	public void setLogWriter(PrintWriter arg0) throws SQLException {
		// TODO Auto-generated method stub
		
	}
 
	@Override
	public void setLoginTimeout(int arg0) throws SQLException {
		// TODO Auto-generated method stub
		
	}
 
	@Override
	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}
 
	@Override
	public <T> T unwrap(Class<T> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}
 
	
 
	@Override
	public Connection getConnection(String username, String password) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}
 
}

寫一個(gè)JdbcUtil測(cè)試數(shù)據(jù)庫(kù)連接池

package jdbcPoolTest;
 
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
public class JdbcUtil {
 
	
	private static JdbcPool jdbcPool = new JdbcPool();
	
	public static Connection getConnection() throws SQLException {
		
		return jdbcPool.getConnection();
		
	}
	//釋放的資源包括Connection數(shù)據(jù)庫(kù)連接對(duì)象,負(fù)責(zé)執(zhí)行SQL命令的Statement對(duì)象,存儲(chǔ)查詢結(jié)果的ResultSet對(duì)象
	public static void release(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();
			}
			rs = null;
		}
	}
}

 db.properties配置文件如下:

driver=com.mysql.jdbc.Driver
 url=jdbc:mysql://localhost:3306/student
 username=root
 password=123456
 jdbcPoolInitSize=10

三、開源數(shù)據(jù)庫(kù)連接池

  現(xiàn)在很多WEB服務(wù)器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的實(shí)現(xiàn),即連接池的實(shí)現(xiàn)。通常我們把DataSource的實(shí)現(xiàn),按其英文含義稱之為數(shù)據(jù)源,數(shù)據(jù)源中都包含了數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)。
  也有一些開源組織提供了數(shù)據(jù)源的獨(dú)立實(shí)現(xiàn):

  • DBCP 數(shù)據(jù)庫(kù)連接池
  • C3P0 數(shù)據(jù)庫(kù)連接池

  在使用了數(shù)據(jù)庫(kù)連接池之后,在項(xiàng)目的實(shí)際開發(fā)中就不需要編寫連接數(shù)據(jù)庫(kù)的代碼了,直接從數(shù)據(jù)源獲得數(shù)據(jù)庫(kù)的連接。

3.1、DBCP數(shù)據(jù)源

  DBCP 是 Apache 軟件基金組織下的開源連接池實(shí)現(xiàn),要使用DBCP數(shù)據(jù)源,需要應(yīng)用程序應(yīng)在系統(tǒng)中增加如下兩個(gè) jar 文件:

  • Commons-dbcp.jar:連接池的實(shí)現(xiàn)
  • Commons-pool.jar:連接池實(shí)現(xiàn)的依賴庫(kù)

  Tomcat 的連接池正是采用該連接池來(lái)實(shí)現(xiàn)的。該數(shù)據(jù)庫(kù)連接池既可以與應(yīng)用服務(wù)器整合使用,也可由應(yīng)用程序獨(dú)立使用。

3.2、在應(yīng)用程序中加入dbcp連接池

  1.導(dǎo)入相關(guān)jar包
        commons-dbcp-1.2.2.jar、commons-pool.jar、common-logging.jar三個(gè)包
  2、在類目錄下加入dbcp的配置文件:dbcpconfig.properties

用了官方的連接池,自然配置文件內(nèi)容也就多了

dbcpconfig.properties的配置信息如下:

 注意這段:

#driver default 指定由連接池所創(chuàng)建的連接的只讀(read-only)狀態(tài)。
 #如果沒(méi)有設(shè)置該值,則“setReadOnly”方法將不被調(diào)用。(某些驅(qū)動(dòng)并不支持只讀模式,如:Informix)
 defaultReadOnly=

如果設(shè)置為ture,那就只能進(jìn)行查詢操作

#連接設(shè)置   報(bào)錯(cuò)com.mysql.jdbc.Connection.isValid(I)Z,更新mysql包
driverClassName=com.mysql.jdbc.Driver
 url=jdbc:mysql://localhost:3306/student
 username=root
 password=123456
 #初始化連接池大小
 jdbcPoolInitSize=10
 #最大連接數(shù)量
 maxActive=50
 
 #<!-- 最大空閑連接 -->
 maxIdle=20
 
 #<!-- 最小空閑連接 -->
 minIdle=5
 
 #<!-- 超時(shí)等待時(shí)間以毫秒為單位 6000毫秒/1000等于60秒 -->
 maxWait=60000
 
 
 #JDBC驅(qū)動(dòng)建立連接時(shí)附帶的連接屬性的格式必須為這樣:[屬性名=property;] 
 #注意:"user" 與 "password" 兩個(gè)屬性會(huì)被明確地傳遞,因此這里不需要包含他們。
 connectionProperties=useUnicode=true;characterEncoding=UTF8
 
 #指定由連接池所創(chuàng)建的連接的自動(dòng)提交(auto-commit)狀態(tài)。
 defaultAutoCommit=true
 
 #driver default 指定由連接池所創(chuàng)建的連接的只讀(read-only)狀態(tài)。
 #如果沒(méi)有設(shè)置該值,則“setReadOnly”方法將不被調(diào)用。(某些驅(qū)動(dòng)并不支持只讀模式,如:Informix)
 defaultReadOnly=
 
 #driver default 指定由連接池所創(chuàng)建的連接的事務(wù)級(jí)別(TransactionIsolation)。
 #可用值為下列之一:(詳情可見(jiàn)javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
 defaultTransactionIsolation=READ_UNCOMMITTED

包結(jié)構(gòu): 

jdbcUtils_DBCP:

大致思路:

1、從配置文件中獲取輸入流,進(jìn)行加載

2、有了BasicDataSoureFactory,那我們也不需要將配置文件中的屬性值一個(gè)一個(gè)讀取出來(lái)了,它有個(gè)方法createDataSource()能自動(dòng)獲取到數(shù)據(jù)源 

3、接下來(lái)只需要拿著這個(gè)數(shù)據(jù)源對(duì)象ds去獲取連接了,具體如何連接,就不需要我們關(guān)心,大致思路與我們自行編寫連接池類似,只不過(guò)多了些其他屬性的出來(lái)方法。從而簡(jiǎn)化了我們的開發(fā)

package zdb.jdbc.util;
 
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
 
import javax.sql.DataSource;
 
import org.apache.commons.dbcp2.BasicDataSourceFactory;
 
 
public class jdbcUtils_DBCP {
 
	/**
	      * 在java中,編寫數(shù)據(jù)庫(kù)連接池需實(shí)現(xiàn)java.sql.DataSource接口,每一種數(shù)據(jù)庫(kù)連接池都是DataSource接口的實(shí)現(xiàn)
	      * DBCP連接池就是java.sql.DataSource接口的一個(gè)具體實(shí)現(xiàn)
	      */
	private  static DataSource ds = null;
	
	
	static {
	InputStream in = jdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
	Properties prop = new Properties();
	try {
		prop.load(in);
		//創(chuàng)建數(shù)據(jù)源
		ds = BasicDataSourceFactory.createDataSource(prop);	 
		
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	}
	public static Connection getConnection() throws SQLException{
		return ds.getConnection();
		
	}
	//釋放的資源包括Connection數(shù)據(jù)庫(kù)連接對(duì)象,負(fù)責(zé)執(zhí)行SQL命令的Statement對(duì)象,存儲(chǔ)查詢結(jié)果的ResultSet對(duì)象
	public static void release(Connection conn,PreparedStatement ps ,ResultSet rs) {
		if (conn!=null) {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (ps!=null) {
			try {
				ps.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();
			}
			rs = null;
		}
	}
	
}

接下來(lái)我們通過(guò)在表中插入屬性值來(lái)測(cè)試--DataSourceTest: 

注意這段:

//由于包版本問(wèn)題:必須加上PreparedStatement.RETURN_GENERATED_KEYS,不然將會(huì)報(bào)主鍵錯(cuò)誤
 ps = conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);

package zdb.jdbc.util;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
 
import javafx.css.PseudoClass;
 
public class DataSourceTest {
	 
	public static void jdbcDataSource() {
		
		PreparedStatement ps = null;
		ResultSet rs = null;
		Connection conn = null;
		try {
			//conn = jdbcUtils_DBCP.getConnection();
			conn = jdbcUtils_DBCP.getConnection();
			String sql = "insert into user(uname) values(?)";
			//由于版本兼容問(wèn)題:必須加上PreparedStatement.RETURN_GENERATED_KEYS
			ps = conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
			ps.setString(1, "lonewolf");
			ps.executeUpdate();
			//獲得主鍵
			rs = ps.getGeneratedKeys();
			if (rs.next()) {
				System.out.println(rs.getInt(1));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch blockrs
			e.printStackTrace();
		}
			finally {
			jdbcUtils_DBCP.release(conn, ps, rs);
			//jdbcUtils_C3P0.release(conn, ps, rs);
		}
		
		
		
	}
 
	public static void main(String[] args) {
		new DataSourceTest().jdbcDataSource();
	}
	
	
}

3.3、C3P0數(shù)據(jù)源(重點(diǎn))

  C3P0是一個(gè)開源的JDBC連接池,它實(shí)現(xiàn)了數(shù)據(jù)源和JNDI綁定,支持JDBC3規(guī)范和JDBC2的標(biāo)準(zhǔn)擴(kuò)展。目前使用它的開源項(xiàng)目有Hibernate,Spring等。C3P0數(shù)據(jù)源在項(xiàng)目開發(fā)中使用得比較多。

  c3p0與dbcp區(qū)別

dbcp默認(rèn)不自動(dòng)回收空閑連接,需要手動(dòng)開啟c3p0默認(rèn)自動(dòng)回收空閑連接功能3.4、在應(yīng)用程序中加入C3P0連接池

  1.導(dǎo)入相關(guān)jar包
       c3p0-0.9.5.2.jar、mchange-commons-java-0.2.12jar,如果操作的是Oracle數(shù)據(jù)庫(kù),那么還需要導(dǎo)入c3p0-oracle-thin-extras-0.9.2-pre1.jar

注意:導(dǎo)入包時(shí),兩個(gè)包的版本也是需要匹配的

不然會(huì)報(bào)錯(cuò):Exception in thread "main" java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector

但是這兩個(gè)包版本是匹配的,下載鏈接c3p0_jar_jb51.rar

       2、包結(jié)構(gòu):


3、在類目錄下加入C3P0的配置文件:c3p0-config.xml,即在項(xiàng)目根目錄下讀取文件

c3p0-config.xml的配置信息如下:

注意:配置文件中有兩種內(nèi)容相似的配置,一種缺省配置,意思是在沒(méi)有指定配置文件名時(shí),調(diào)用該配置,一種命名配置,也就是在使用配置文件時(shí),加上配置名即可引用,如接下來(lái)會(huì)說(shuō)的:new ComboPooledDataSource("MySQL");

<c3p0-config>
     <!--
     C3P0的缺省(默認(rèn))配置,
     如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource();”這樣寫就表示使用的是C3P0的缺省(默認(rèn))配置信息來(lái)創(chuàng)建數(shù)據(jù)源
     -->
     <default-config>
         <property name="driverClass">com.mysql.jdbc.Driver</property>
         <property name="jdbcUrl">jdbc:mysql://localhost:3306/student</property>
         <property name="user">root</property>
         <property name="password">123456</property>
         
         <property name="acquireIncrement">5</property>
         <property name="initialPoolSize">10</property>
         <property name="minPoolSize">5</property>
         <property name="maxPoolSize">20</property>
     </default-config>
 
     <!--
     C3P0的命名配置,
     如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”這樣寫就表示使用的是name是MySQL的配置信息來(lái)創(chuàng)建數(shù)據(jù)源
     -->
     <named-config name="MySQL">
         <property name="driverClass">com.mysql.jdbc.Driver</property>
         <property name="jdbcUrl">jdbc:mysql://localhost:3306/student</property>
         <property name="user">root</property>
         <property name="password">123456</property>
         
         <property name="acquireIncrement">5</property>
         <property name="initialPoolSize">10</property>
         <property name="minPoolSize">5</property>
         <property name="maxPoolSize">20</property>
     </named-config>
 
 </c3p0-config>

jdbcUtils_C3P0:

大致思路:

 我們可以通過(guò)代碼看到,c3p0將我們的代碼量又縮減了許多

ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");我們直接new一個(gè)ComboPooledDataSource()對(duì)象就可以獲得數(shù)據(jù)源,所以這就是為什么之前需要將xml配置文件放在根目錄下,“MySQL”就是我們的配置的名字

package zdb.jdbc.util;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import com.mchange.v2.c3p0.ComboPooledDataSource;
 
public class jdbcUtils_C3P0 {
	
	private static ComboPooledDataSource ds = null;
	static {
		ds = new ComboPooledDataSource("MySQL");
		
	}
	public static Connection getConnection() throws SQLException{
	    //從數(shù)據(jù)源中獲取數(shù)據(jù)庫(kù)連接
	    return ds.getConnection();
}
	//釋放的資源包括Connection數(shù)據(jù)庫(kù)連接對(duì)象,負(fù)責(zé)執(zhí)行SQL命令的Statement對(duì)象,存儲(chǔ)查詢結(jié)果的ResultSet對(duì)象
		public static void release(Connection conn,PreparedStatement ps ,ResultSet rs) {
			if (conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (ps!=null) {
				try {
					ps.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();
				}
				rs = null;
			}
		}
 
}

 測(cè)試C3P0數(shù)據(jù)源-DataSourceTest

package zdb.jdbc.util;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
 
import javafx.css.PseudoClass;
 
public class DataSourceTest {
	 
	public static void jdbcDataSource() {
		
		PreparedStatement ps = null;
		ResultSet rs = null;
		Connection conn = null;
		try {
			//conn = jdbcUtils_DBCP.getConnection();
			conn = jdbcUtils_C3P0.getConnection();
			String sql = "insert into user(uname) values(?)";
			//由于版本兼容問(wèn)題:必須加上PreparedStatement.RETURN_GENERATED_KEYS
			ps = conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
			ps.setString(1, "lonewolf");
			ps.executeUpdate();
			//獲得主鍵
			rs = ps.getGeneratedKeys();
			if (rs.next()) {
				System.out.println(rs.getInt(1));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch blockrs
			e.printStackTrace();
		}
			finally {
			jdbcUtils_DBCP.release(conn, ps, rs);
			//jdbcUtils_C3P0.release(conn, ps, rs);
		}
		
		
		
	}
 
	public static void main(String[] args) {
		new DataSourceTest().jdbcDataSource();
	}
	
	
}

這些便是數(shù)據(jù)庫(kù)連接池的大致內(nèi)容。

接下來(lái)說(shuō)說(shuō)

四、Tomcat中配置數(shù)據(jù)庫(kù)源

在實(shí)際開發(fā)中,我們有時(shí)候還會(huì)使用服務(wù)器提供給我們的數(shù)據(jù)庫(kù)連接池,比如我們希望Tomcat服務(wù)器在啟動(dòng)的時(shí)候可以幫我們創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接池,那么我們?cè)趹?yīng)用程序中就不需要手動(dòng)去創(chuàng)建數(shù)據(jù)庫(kù)連接池,直接使用Tomcat服務(wù)器創(chuàng)建好的數(shù)據(jù)庫(kù)連接池即可。要想讓Tomcat服務(wù)器在啟動(dòng)的時(shí)候幫我們創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接池,那么需要簡(jiǎn)單配置一下Tomcat服務(wù)器。

4.1、JNDI技術(shù)簡(jiǎn)介

  JNDI(Java Naming and Directory Interface),Java命名和目錄接口,它對(duì)應(yīng)于J2SE中的javax.naming包,
  這 套API的主要作用在于:它可以把Java對(duì)象放在一個(gè)容器中(JNDI容器),并為容器中的java對(duì)象取一個(gè)名稱,以后程序想獲得Java對(duì)象,只需 通過(guò)名稱檢索即可。其核心API為Context,它代表JNDI容器,其lookup方法為檢索容器中對(duì)應(yīng)名稱的對(duì)象。

  Tomcat服務(wù)器創(chuàng)建的數(shù)據(jù)源是以JNDI資源的形式發(fā)布的,所以說(shuō)在Tomat服務(wù)器中配置一個(gè)數(shù)據(jù)源實(shí)際上就是在配置一個(gè)JNDI資源

服務(wù)器創(chuàng)建好數(shù)據(jù)源之后,我們的應(yīng)用程序又該怎么樣得到這個(gè)數(shù)據(jù)源呢,Tomcat服務(wù)器創(chuàng)建好數(shù)據(jù)源之后是以JNDI的形式綁定到一個(gè)JNDI容器中的,我們可以把JNDI想象成一個(gè)大大的容器,我們可以往這個(gè)容器中存放一些對(duì)象,一些資源,JNDI容器中存放的對(duì)象和資源都會(huì)有一個(gè)獨(dú)一無(wú)二的名稱,應(yīng)用程序想從JNDI容器中獲取資源時(shí),只需要告訴JNDI容器要獲取的資源的名稱,JNDI根據(jù)名稱去找到對(duì)應(yīng)的資源后返回給應(yīng)用程序。我們平時(shí)做javaEE開發(fā)時(shí),服務(wù)器會(huì)為我們的應(yīng)用程序創(chuàng)建很多資源,比如request對(duì)象,response對(duì)象,服務(wù)器創(chuàng)建的這些資源有兩種方式提供給我們的應(yīng)用程序使用:第一種是通過(guò)方法參數(shù)的形式傳遞進(jìn)來(lái),比如我們?cè)赟ervlet中寫的doPost和doGet方法中使用到的request對(duì)象和response對(duì)象就是服務(wù)器以參數(shù)的形式傳遞給我們的。第二種就是JNDI的方式,服務(wù)器把創(chuàng)建好的資源綁定到JNDI容器中去,應(yīng)用程序想要使用資源時(shí),就直接從JNDI容器中獲取相應(yīng)的資源即可。

  對(duì)于上面的name="jdbc/datasource"數(shù)據(jù)源資源,在應(yīng)用程序中可以用如下的代碼去獲取

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
dataSource = (DataSource)envCtx.lookup("jdbc/datasource");

此種配置下,數(shù)據(jù)庫(kù)的驅(qū)動(dòng)jar文件需放置在tomcat的lib下

4.2、配置Tomcat數(shù)據(jù)源 包結(jié)構(gòu):

 如果報(bào)錯(cuò)com.mysql.jdbc.Connection.isValid(I)Z,說(shuō)明包太舊了,更新mysql包即可解決

配置數(shù)據(jù)源JNDI的方式有很多,詳細(xì)請(qǐng)看:http://www.dbjr.com.cn/article/213425.htm

注意了:有個(gè)問(wèn)題坑了我一天

先看我的這篇文章---解決Tomcat中修改server.xml和content.xml后自動(dòng)還原問(wèn)題:http://www.dbjr.com.cn/article/213429.htm

之前我是直接在外部的tomcat文件下的conf文件夾下去修改這兩個(gè)文件,所以落坑

看完這篇文章應(yīng)該知道了server.xml、context.xml的大概配置,接下來(lái),我們來(lái)具體配置

我使用---配置全局JNDI數(shù)據(jù)源,應(yīng)用到所有Tomcat下部署的應(yīng)用

第一步、找到Tomcat的server.xml中GlobalNamingResources節(jié)點(diǎn),在節(jié)點(diǎn)下加一個(gè)全局?jǐn)?shù)據(jù)源

注意:name="jdbc/mysql"中“jdbc/mysql”為數(shù)據(jù)源名,在文件中多處引用  

<Resource  
    name="jdbc/mysql"   
    scope="Shareable"   
    type="javax.sql.DataSource"  
    factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"  
    url="jdbc:mysql://localhost:3306/test"  
    driverClassName ="com.mysql.jdbc.Driver"  
    username="root"  
    password="root"  
/>  

第二步,找到Tomcat的context.xml,在Context節(jié)點(diǎn)下加一個(gè)ResourceLink節(jié)點(diǎn)對(duì)第一步配置的數(shù)據(jù)源進(jìn)行引用

這個(gè)XML配置文件的根節(jié)點(diǎn)就是<Context>

 插入代碼:

<ResourceLink global="jdbc/mysql" name="jdbc/mysql" type="javax.sql.DataSource"/>

 第三步,配置web.xml文件,添加資源映射(此步驟可要可不要

 <resource-ref>
   <description>DB Connection</description>
   <res-ref-name>jdbc/mysql</res-ref-name>
   <res-type>javax.sql.DataSource</res-type>
   <res-auth>Container</res-auth>
 </resource-ref> 

這種配置方式 

優(yōu)點(diǎn):重用性,一次性到位

缺點(diǎn):沒(méi)有可控性(tomcat原始文件遭到修改)

 配置文件配置好了,現(xiàn)在就來(lái)寫代碼

JdbcUtils_JNDI:

package zdb.util.JNDI_tomcat;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
 
public class JdbcUtils_JNDI {
	private static DataSource ds = null;
	static {
		
		try {
			//初始化JNDI
			Context initCtx = new InitialContext();
			//得到JNDI容器
			Context envCtx = (Context) initCtx.lookup("java:comp/env");
			//從JNDI容器中檢索name為jdbc/datasource的數(shù)據(jù)源
			ds = (DataSource) envCtx.lookup("jdbc/mysql");
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	public static Connection getConnection() throws SQLException{
	    //從數(shù)據(jù)源中獲取數(shù)據(jù)庫(kù)連接
		
	    return ds.getConnection();
	   
}
	//釋放的資源包括Connection數(shù)據(jù)庫(kù)連接對(duì)象,負(fù)責(zé)執(zhí)行SQL命令的Statement對(duì)象,存儲(chǔ)查詢結(jié)果的ResultSet對(duì)象
		public static void release(Connection conn,PreparedStatement ps ,ResultSet rs) {
			if (conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (ps!=null) {
				try {
					ps.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();
				}
				rs = null;
			}
 
}
}

 測(cè)試下

JNDI_test:

package zdb.util.JNDI_tomcat;
 
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/JNDI_test")
public class JNDI_test extends HttpServlet{
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
	             throws ServletException, IOException {
	         Connection conn = null;
	         PreparedStatement st = null;
	         ResultSet rs = null;
	         try{
	             //獲取數(shù)據(jù)庫(kù)連接
	             conn = JdbcUtils_JNDI.getConnection();
	             System.out.println("mysql Connection pool connected !!");
	             String sql = "insert into user(uname) values(?)";
	             st = conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
	             st.setString(1, "gacl");
	             st.executeUpdate();
	             //獲取數(shù)據(jù)庫(kù)自動(dòng)生成的主鍵
	             rs = st.getGeneratedKeys();
	             if(rs.next()){
	                 System.out.println(rs.getInt(1));
	             }
	         }catch (Exception e) {
	             e.printStackTrace();
	         }finally{
	             //釋放資源
	             JdbcUtils_JNDI.release(conn, st, rs);
	         }
	     }
	 public void doPost(HttpServletRequest request, HttpServletResponse response)
	              throws ServletException, IOException {
	          doGet(request, response);
	     }
 
}

 我再通過(guò)寫一個(gè)jsp頁(yè)面來(lái)映射到該servlet測(cè)試下

test.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style>
	body{
	text-align:center;
	}	
</style>
</head>
<body>
	<a href="${pageContext.servletContext.contextPath }/JNDI_test" rel="external nofollow" >測(cè)試</a>
	
</body>

測(cè)試結(jié)果成功:

拓展:由于此種配置模式的缺點(diǎn),我們還可以通過(guò)增加一個(gè)新的xml文件來(lái)增加節(jié)點(diǎn),而不用動(dòng)原始文件

具體請(qǐng)看:tomcat虛擬路徑的配置

幾篇文章推薦給大家看下:

tomcat下面web應(yīng)用發(fā)布路徑配置( 即虛擬目錄配置 ):http://www.voidcn.com/article/p-zctzsjte-rs.html

Tomcat服務(wù)器原理詳解:https://www.cnblogs.com/crazylqy/p/4706223.html

Tomcat中主目錄配置與虛擬目錄配置問(wèn)題自我總結(jié):http://blog.51cto.com/longx/1357666

文章借鑒參照:-孤傲蒼狼-原文:https://www.cnblogs.com/xdp-gacl/p/4002804.html

到此這篇關(guān)于Java中幾種常用數(shù)據(jù)庫(kù)連接池的使用的文章就介紹到這了,更多相關(guān)Java 數(shù)據(jù)庫(kù)連接池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Springboot項(xiàng)目中如何讓非Spring管理的類獲得一個(gè)注入的Bean

    Springboot項(xiàng)目中如何讓非Spring管理的類獲得一個(gè)注入的Bean

    這篇文章主要介紹了Springboot項(xiàng)目中如何讓非Spring管理的類獲得一個(gè)注入的Bean問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 詳解Java關(guān)鍵字final

    詳解Java關(guān)鍵字final

    今天帶大家學(xué)習(xí)Java基礎(chǔ)知識(shí),文中對(duì)關(guān)鍵字final作了非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)Java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • java實(shí)現(xiàn)四子棋游戲

    java實(shí)現(xiàn)四子棋游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)四子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • Java本地緩存工具之LoadingCache的使用詳解

    Java本地緩存工具之LoadingCache的使用詳解

    緩存,在我們?nèi)粘i_發(fā)中是必不可少的一種解決性能問(wèn)題的方法。簡(jiǎn)單的說(shuō),cache?就是為了提升系統(tǒng)性能而開辟的一塊內(nèi)存空間。本文將為大家介紹一個(gè)Java本地緩存的工具——LoadingCache,感興趣的可以了解一下
    2021-12-12
  • J2SE基礎(chǔ)之命令行中編寫第一個(gè) Hello World

    J2SE基礎(chǔ)之命令行中編寫第一個(gè) Hello World

    “Hello World”程序指的是只在計(jì)算機(jī)屏幕上輸出“Hello, World!”(意為“世界,你好!”)這行字符串的計(jì)算機(jī)程序。hello world作為所有編程語(yǔ)言的起始階段,占據(jù)著無(wú)法改變的地位,所有的編程第一步就在于此了!經(jīng)典之中的經(jīng)典!hello world!
    2016-05-05
  • spring boot 即時(shí)重新啟動(dòng)(熱更替)使用說(shuō)明

    spring boot 即時(shí)重新啟動(dòng)(熱更替)使用說(shuō)明

    這篇文章主要介紹了spring boot 即時(shí)重新啟動(dòng)(熱更替)的相關(guān)資料,需要的朋友可以參考下
    2017-12-12
  • Java并發(fā)之嵌套管程鎖死詳解

    Java并發(fā)之嵌套管程鎖死詳解

    這篇文章主要介紹了Java并發(fā)之嵌套管程鎖死詳解,涉及嵌套管程鎖死的發(fā)生,實(shí)例等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 詳解SpringBoot如何自定義注解

    詳解SpringBoot如何自定義注解

    注解,也叫元數(shù)據(jù),一種代碼級(jí)別的說(shuō)明,它是JDK1.5及以后版本引入的一個(gè)特性,與類、接口、枚舉是在同一個(gè)層次,本文給大家詳細(xì)介紹了SpringBoot如何自定義注解,文中通過(guò)代碼講解的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • spring cloud openfeign 源碼實(shí)例解析

    spring cloud openfeign 源碼實(shí)例解析

    這篇文章主要介紹了spring cloud openfeign 源碼實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Spring和SpringMVC父子容器關(guān)系初窺(小結(jié))

    Spring和SpringMVC父子容器關(guān)系初窺(小結(jié))

    這篇文章主要介紹了Spring和SpringMVC父子容器關(guān)系初窺(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論