MySQL---第三方连接池---dbcp

18 篇文章 1 订阅

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/>&emsp;&emsp;&emsp;&ensp; 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;
		}

		@Override
		public 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);
					}
				}
			}
		};
	}
}

源码链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值