使用jdbc时,每一次 操作都需要创建一个连接,然后销毁掉,可以通过连接池来进行资源的优化。
管理数据库的连接,提高系统性能,就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可.所有的连接池必须实现一个接口 javax.sql.DataSource接口。
Connection getConnection()
connection.close()
/**
* 20190802
* 自定义一个连接池 重点在于理解连接池的思想
* 就是先建立好若干数量的数据库连接 都放在一个“池子”里 有需要的时候 就申请从这个池子里获取
* 试用完了 就把连接归还回来即可
*/
public class MyDataSource {
//用来存放连接的连接池
static LinkedList<Connection> pool = new LinkedList<>();
static int linkNum = 3;//连接池数量上限
//初始化
static {
for (int i=0; i<linkNum; i++){
try {
Connection conn = JDBCUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//从连接池中获取连接
public static Connection getConnection(){
//先要判断连接池中是否还有连接
//若没有 先扩容
if (pool.isEmpty()){
for (int i=0; i<linkNum; i++){
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("从连接池获取一个连接");
return pool.removeFirst();
}
/**
* 20190802
* 归还连接
* @param conn
*/
public static void addBack(Connection conn){
//将conn放在poll末尾即可
pool.addLast(conn);
System.out.println("归还一条连接");
}
/**
* 20190802
* 测试自定义的连接池
*/
public class TestMyDS {
public static void main(String[] args) {
//创建连接池
MyDataSource ds = new MyDataSource();
//获取连接
Connection conn = ds.getConnection();
System.out.println(conn);
//归还连接
ds.addBack(conn);
}
}
上述连接池归还连接的时候多了一个方法叫
addBack()
,但是标准的归还应该是close
方法,但是在自定义工具类的时候,close
方法实现的是销毁连接的功能,如何在不改变方法名和功能的时候,让同一个方法做更多的事情。
这里的问题本质上就是如何对一个方法进行增强,一般有三种方式:
下面详细讲解装饰者模式
定义了一个汽车接口,具有
run
和stop
的两种方法,一个具体的汽车Audi实现了这个接口,以5m/s
的速度run
,希望增强这个方法,让Audi的速度达到50m/s
1.定义接口
public interface Car {
void run();
void stop();
}
2.定义Audi类,实现接口
public class Audi implements Car {
@Override
public void run() {
System.out.println("5m/s");
}
@Override
public void stop() {
System.out.println("stopping");
}
}
3.定义装饰者,实现Car接口,并增强方法
public class CarWrap implements Car {
private Car car;
/**
* 构造函数 对所有继承了 Car接口的类都起作用
* @param car
*/
public CarWrap(Car car){
this.car = car;
}
//增强方法
@Override
public void run(){
System.out.println("speeding");
System.out.println("50m/s");
}
@Override
public void stop(){
//不需要增强的方法 调用原方法即可
car.stop();
}
}
4.使用包装类
public class Test {
public static void main(String[] args) {
Audi audi = new Audi();
audi.run();
audi.stop();
//测试装饰者模式
// 对audi这个对象 增强
CarWrap carWrap = new CarWrap(audi);
//调用run方法可以发现 该方法执行的是被增强后的代码
carWrap.run();
carWrap.stop();
}
}
Connection.close()
方法归还连接建立一个装饰者继承
Connection
类 然后对Connection.close()
方法进行增强
close
方法public class ConnectionWrap implements Connection {
private Connection conn;
private LinkedList<Connection> pool;
//构造方法 因为后面的close方法需要将一个连接归还给 pool,而pool是自定义的连接池实现的,所以需要在
//装饰者类 初始化的时候 传进来
public ConnectionWrap(Connection conn, LinkedList<Connection> pool){
this.conn = conn;
this.pool = pool;
}
/**
* 20190802
* close方法 需要增强的方法
* @throws SQLException
*/
@Override
public void close() throws SQLException {
System.out.println("前:" + pool.size());
//当前连接归还到连接池
pool.addLast(this);
System.out.println("后:" + pool.size());
System.out.println("归还一条连接到连接池");
}
/**
* 不需要增强的方法 调用原始方法即可
* @return
* @throws SQLException
*/
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
//不需要增强的方法 调用原始方法即可
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
}
MyDataSourceWrap
关键在于 拿到连接后 需要经过装饰者装饰后才能返回
public class MyDataSourceWrap {
//用来存放连接的连接池
static LinkedList<Connection> pool = new LinkedList<>();
static int linkNum = 3;//连接池数量上限
//初始化
//静态代码块 在类被加载的时候 就执行了
static {
for (int i=0; i<linkNum; i++){
try {
Connection conn = JDBCUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//从连接池中获取连接
/**
* 使用装饰者模式 实现close归还连接
* @return
*/
public static Connection getConnection(){
//先要判断连接池中是否还有连接
//若没有 先扩容
if (pool.isEmpty()){
for (int i=0; i<linkNum; i++){
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("从连接池获取一个连接");
Connection conn = pool.removeFirst();
//这里获取到的连接 需要先被装饰后传出 才会具有close的效果
ConnectionWrap myconn = new ConnectionWrap(conn, pool);
return myconn;
}
直接使用Connection.close即可归还连接到连接池
public class TestMyDSWrap {
public static void main(String[] args) throws SQLException {
//创建连接池
MyDataSourceWrap ds = new MyDataSourceWrap();
//获取连接
Connection conn = ds.getConnection();
System.out.println(conn);
//归还连接
conn.close();
}
}
apache组织开发的
使用步骤
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/day07");
ds.setUsername("root");
ds.setPassword("admin");
.properties
文件,以key=value
存放配置参数,注意里面的key和前文配置文件中的key不一样。DataSource ds = new BasicDataSourceFactory().createDataSource(prop);
//存放配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("src/dbcp.properties"));
//创建连接池
DataSource ds = new BasicDataSourceFactory().createDataSource(prop);
hibernate和spring框架都使用了该连接池,有自动回收空闲连接功能。
1.导入jar包(c3p0-0.9.1.2.jar)
2.使用api
//建立连接池
ComboPooledDataSource ds = new ComboPooledDataSource();
//设置基本参数
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///day07");
ds.setUser("root");
ds.setPassword("admin");
c3p0.properties
,注意配置文件的命名必须规范c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///day07
c3p0.user=root
c3p0.password=admin
//建立连接池
//可以看到 这里并没有任何关于配置文件的信息
//说明配置文件按照规范的位置 和命名 c3p0可以自己查到
ComboPooledDataSource ds = new ComboPooledDataSource();
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<!-- 基本配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/day07</property>
<property name="user">root</property>
<property name="password">admin</property>
<!--扩展配置-->
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
//建立连接池
//可以看到 这里并没有任何关于配置文件的信息
//说明配置文件按照规范的位置 和命名 c3p0可以自己查到
ComboPooledDataSource ds = new ComboPooledDataSource();
Connection conn=ds.getConnection();
配置文件的c3p0-config.xml的命名配置方式