現在很多WEB服務器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的實現,即連接池的實現。通常我們把DataSource的實現,按其英文含義稱之爲數據源,數據源中都包含了數據庫連接池的實現。
也有一些開源組織提供了數據源的獨立實現:
DBCP 數據庫連接池
C3P0 數據庫連接池
實際應用時不需要編寫連接數據庫代碼,直接從數據源獲得數據庫的連接。程序員編程時也應儘量使用這些數據源的實現,以提升程序的數據庫訪問性能。
DBCP數據源
DBCP 是 Apache 軟件基金組織下的開源連接池實現,使用DBCP數據源,應用程序應在系統中增加如下兩個 jar 文件:
Commons-dbcp.jar:連接池的實現
Commons-pool.jar:連接池實現的依賴庫
Tomcat 的連接池正是採用該連接池來實現的。該數據庫連接池既可以與應用服務器整合使用,也可由應用程序獨立使用。
dbcp數據庫連接池的兩種實現方式
package cn.hncu.dbcp;
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;
public class DbcpPoolDemo {
//dbcp數據庫連接池----BasicDataSource類對象
//使用配置文件的方式--利用BasicDataSourceFactory工廠類+Properties的方式創建,參數直接從配置文件讀取
@Test
public void demo2() throws Exception{
Properties p=new Properties();
//src目錄下的--配置文件放在classpath下,則可用下面一行來獲取
// p.load(DbcpPoolDemo.class.getClassLoader().getResourceAsStream("dbcp.properties"));
//配置文件和當前類放在一起
p.load(DbcpPoolDemo.class.getResourceAsStream("dbcp2.properties"));
DataSource pool=BasicDataSourceFactory.createDataSource(p);
// Connection con=pool.getConnection();
// System.out.println("con:"+con);
for(int i=0;i<30;i++){//默認是八個,可以通過資源文件(dbcp2.properties)更改
Connection con=pool.getConnection();
System.out.println(con.hashCode());//輸出8個(pool.getMaxActive())之後就阻塞了
}
}
@Test//純Java方式 ---利用空參構造方式BasicDataSource()創建,然後通過setter方法手動設置參數
public void demo1() throws Exception{
BasicDataSource pool=new BasicDataSource();
pool.setDriverClassName("com.mysql.jdbc.Driver");
pool.setUrl("jdbc:mysql://127.0.0.1:3306/hncu?useUnicode=true&characterEncoding=utf-8");
pool.setUsername("root");
pool.setPassword("1234");
// Connection con=pool.getConnection();
// System.out.println(con);
System.out.println("初始連接的個數:"+pool.getInitialSize());//0
System.out.println("最多能有幾個在用的連接:"+pool.getMaxActive());//8
System.out.println("最多空閒多長時間(若沒使用該連接就收回):"+pool.getMaxIdle());//8
System.out.println("最多等待多長時間(若沒獲得連接就拋出異常):"+pool.getMaxWait());//-1
//可以自己更改池的參數
pool.setMaxActive(10);
/*
* 以下測試從池獲取多個連接
*/
for(int i=0;i<15;i++){
Connection con=pool.getConnection();
System.out.println(con.hashCode());//輸出8個(pool.getMaxActive())之後就阻塞了
if(i%2==0){//dbcp池中如果有最近使用的連接con,就不會新開一個連接con,而是使用最近用的con
con.close();
}
}
System.out.println("Over....");
}
}
dbcp.properties放在src目錄下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/hncu?useUnicode=true&characterEncoding=utf-8
username=root
password=1234
size=3
開源數據庫連接池
package cn.hncu.dbcp;
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class DbcpUtils {
//本地線程管理對象,用於實現: 同一個線程獲取的連接是同一個
private static ThreadLocal<Connection> t = new ThreadLocal<Connection>();
private static DataSource pool = null;
static{
Properties p = new Properties();
try {
//配置文件和當前類放在一起
p.load(DbcpUtils.class.getResourceAsStream("dbcp2.properties"));
pool= BasicDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConn() {
//先從t中拿,如果有就拿出去,如果沒有再到池中拿且把該對象放到t中
Connection con = t.get();
if(con==null){
try {
con=pool.getConnection();
t.set(con); //放到t中
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
System.out.println("獲取一個連接:"+con);
return con;
}
}
dbcp2.properties和當前類放在一起
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/hncu?useUnicode=true&characterEncoding=utf-8
username=root
password=1234
maxActive=15
package cn.hncu.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.UUID;
import org.junit.Test;
import cn.hncu.dbcp.DbcpUtils;
public class DbcpTest {
@Test
public void demo() throws Exception{
Connection con=DbcpUtils.getConn();
System.out.println("demo-con:"+con);
try {
con.setAutoCommit(false);
saveStud();
saveStud2();
con.commit();
System.out.println("提交一個事務...");
} catch (SQLException e) {
con.rollback();
System.out.println("回滾一個事務...");
}finally{
con.setAutoCommit(true);//還原現場
con.close();
}
}
public void saveStud() throws Exception{
Connection con=DbcpUtils.getConn();
System.out.println("saveStud-con:"+con);
String sql="INSERT INTO stud VALUES(?,?)";
PreparedStatement pst=con.prepareStatement(sql);
for(int i=0;i<2;i++){
String id=UUID.randomUUID().toString().replace("-", "");
pst.setString(1, id);
pst.setString(2, "stud"+i);
pst.addBatch();
}
pst.executeBatch();
}
public void saveStud2() throws Exception{
Connection con=DbcpUtils.getConn();
System.out.println("saveStud2-con:"+con);
String sql="insert into stud values(?,?)";
PreparedStatement pst=con.prepareStatement(sql);
for(int i=3;i<5;i++){
String id=UUID.randomUUID().toString().replace("-", "");
pst.setString(1, id);
// pst.setString(1, "70e56717e7634c9c85aefcad6560afd1");//測試事務回滾
pst.setString(2, "stud"+i);
pst.addBatch();
}
pst.executeBatch();
}
}