DataSource接口
sun公司提供了javax.sql.DataSource接口,所有第三方的数据库连接池都必须实现该接口。
dbcp
需要jar包:apache.commons.pool-1.5.3.jar 和 commons-dbcp-1.4.jar,还有最基本的 mysql-connector-java-5.1.35-bin.jar。
下面是不使用配置文件的形式:
@Test //技术入口: org.apache.commons.dbcp.BasicDataSource public void demo1() throws SQLException {//下面这一句相当于创建了一个池BasicDataSource bds = new BasicDataSource();//下面开始给这个池配置信息。bds.setDriverClassName("com.mysql.jdbc.Driver");bds.setUrl("jdbc:mysql://127.0.0.1:3306/hncu?useUnicode=true&characterEncoding=utf-8");bds.setUsername("root");bds.setPassword("1234");//接下来就可以获取连接了,进行查询了。Connection con = bds.getConnection();Statement st = con.createStatement();ResultSet resultSet = st.executeQuery("show databases");while ( resultSet.next() ) {System.out.println( resultSet.getString(1) );}System.out.println("------------------------------");//通过bds还可获取连接池的详细信息。System.out.println("连接池最多有多少个连接:"+ bds.getMaxActive() );System.out.println("连接池最多有多少个连接处于空闲:"+ bds.getMaxIdle() );System.out.println("连接池初始化大小:"+ bds.getInitialSize() );System.out.println("连接的等待时间的最大值:"+ bds.getMaxWait() );//还有其他信息。。。}
使用配置文件,该方式面向接口。
//演示通过 配置文件 初始化连接池,该方式面向接口编程,扩展性较好//技术入口:BasicDataSourceFactory.createDataSource(p);public static void main( String[] args) throws Exception {Properties p = new Properties();//加载配置文件方式1:该方式可以加载与当前类所在同一个包中的配置文件//p.load(DbcpHello.class.getResourceAsStream("dbcp.properties"));//加载配置文件方式2:该方式可以加载classPath下配置文件p.load( DbcpHello.class.getClassLoader().getResourceAsStream("cn/hncu/dbPool/dbcp/dbcp.properties"));DataSource ds = BasicDataSourceFactory.createDataSource(p);//接下来就可以获取连接了,进行查询了。Connection con = ds.getConnection();Statement st = con.createStatement();ResultSet resultSet = st.executeQuery("show databases");while ( resultSet.next() ) {System.out.println( resultSet.getString(1) );}System.out.println("-----------------");for(int i = 0; i<20;i++) {try {Connection con2 = ds.getConnection();System.out.println(con2.hashCode());if( i%2 == 0) {con2.close();}} catch (Exception e) {e.printStackTrace();}}}
采用dbcp连接池+ThreadLocal制作一个工具类:实现一个线程最多只能有一个连接。
工具类
package cn.hncu.dbPool.dbcp;import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp.BasicDataSourceFactory;/*** dbcp连接池工具* <br/><br/><b>CreateTime:</b><br/>     2018年9月23日 上午8:40:41 * @author 宋进宇 Email:447441478@qq.com*/
public class DbcpUtils {//数据库连接池private static DataSource ds; //线程局部变量池---为实现一个线程最多只能拥有一个连接private static ThreadLocal<Connection> tlPool = new ThreadLocal<Connection>();//私有化构造函数private DbcpUtils() {}//初始化dbcp连接池static {try {//创建配置文件对象Properties p = new Properties();//加载配置文件信息p.load( DbcpHello.class.getClassLoader().getResourceAsStream("cn/hncu/dbPool/dbcp/dbcp.properties"));//通过工厂生产连接池ds = BasicDataSourceFactory.createDataSource(p);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e.getMessage(),e);}}/*** 向外提供连接池* @return 连接池对象*/public static DataSource getDataSource() {return ds;}public static Connection getConnection() throws SQLException {//先从线程局部变量池中获取当前线程拥有数据库连接Connection con = tlPool.get();//如果当前线程拥有的数据库连接为null或者是Closed状态,那么从连接池中获取一个连接if( con == null || con.isClosed() ) {//从连接池中获取一个连接con = ds.getConnection();//把获取到的连接放到线程局部变量池中,以便同一个线程共享一个数据库连接。tlPool.set(con);}return con;}
}
测试工具类是否能够到达需求
package cn.hncu.dbPool.dbcp;import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;/* 经过测试发现 dbcp连接池是采用栈的数据结构来做的,而且内存是固定的,* 当一个连接con是closed的状态时,dbcp会清空con所指向的内存的数据,并且把con返回栈中。* 当调用getConnection时,dbcp会从栈顶取出一个con,如果con所指向的内存的数据为空,* 就会在con所指向的内存区域重新初始化一个con对象。*/
public class DbcpUtilsTest {public static void main(String[] args) {Connection con = null;try {con = DbcpUtils.getConnection();System.out.println(Thread.currentThread().getName()+">>"+con.hashCode());con.setAutoCommit(false); //开启事务save1(1);new MyThread(1).start();save2(1);con.commit(); //事务提交System.out.println("m1事务提交了...");} catch (SQLException e) {//e.printStackTrace();try {con.rollback();System.out.println("m1事务回滚了...");} catch (SQLException e1) {throw new RuntimeException(e.getMessage(),e);}} finally {if( con != null ) {try {//还原con.setAutoCommit(true);//关闭con.close();} catch (SQLException e) {throw new RuntimeException(e.getMessage(),e);}}}new MyThread(2).start(); try {Thread.sleep(1);} catch (InterruptedException e2) {e2.printStackTrace();}/* 如果下面的注释掉的话,上面这个线程中con的hashcode与Main线程的hashcode一样。*///*try {con = DbcpUtils.getConnection();System.out.println(Thread.currentThread().getName()+">>"+con.hashCode());con.setAutoCommit(false); //开启事务save1(2);Statement st = con.createStatement();//使出现错误st.executeQuery("select");con.commit(); //事务提交System.out.println("m2事务提交了...");} catch (Exception e) {//e.printStackTrace();try {con.rollback();System.out.println("m2事务回滚了...");} catch (SQLException e1) {throw new RuntimeException(e.getMessage(),e);}} finally {if( con != null ) {try {//还原con.setAutoCommit(true);//关闭con.close();} catch (SQLException e) {throw new RuntimeException(e.getMessage(),e);}}}//*/}public static void save1(int i) throws SQLException {Connection con = DbcpUtils.getConnection();System.out.println(Thread.currentThread().getName()+">save1>"+con.hashCode());Statement st = con.createStatement();st.executeUpdate("insert into student values('A001"+Thread.currentThread().getName()+i+"','Jack')");st.executeUpdate("insert into student values('A002"+Thread.currentThread().getName()+i+"','Tom"+i+"')");st.close();}public static void save2(int i)throws SQLException {Connection con = DbcpUtils.getConnection();System.out.println(Thread.currentThread().getName()+">save2>"+con.hashCode());Statement st = con.createStatement();st.executeUpdate("insert into student values('B001"+Thread.currentThread().getName()+i+"','Rose')");st.executeUpdate("insert into student values('B002"+Thread.currentThread().getName()+i+"','Alice')");st.close();}static class MyThread extends Thread{int num;protected MyThread(int num) {this.num = num;}@Overridepublic void run() {Connection con = null;try {con = DbcpUtils.getConnection();System.out.println(Thread.currentThread().getName()+">>"+con.hashCode());con.setAutoCommit(false); //开启事务save1(num);save2(num);
// if( num % 2 == 0) {
// Statement st = con.createStatement();
// //使出现错误
// st.executeQuery("11111111");
// }con.commit(); //事务提交System.out.println(num+">>事务提交了...");} catch (SQLException e) {//e.printStackTrace();try {con.rollback();System.out.println(num+">>事务回滚了...");} catch (SQLException e1) {throw new RuntimeException(e.getMessage(),e);}} finally {if( con != null ) {try {//还原con.setAutoCommit(true);//关闭con.close();} catch (SQLException e) {throw new RuntimeException(e.getMessage(),e);}}}};}
}