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:[email protected]
*/
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);
}
}
}
};
}
}