为什么要有数据库连接池
1.创建Connection的过程是很耗时的
2.一个Connection只能供一个对象使用(所以不能使用单例模式)
3.所以要先创建一堆连接,要一个给你一个,用完了还回来。
什么是代理模式
龙哥总结:
从静态代理的使用上来看,我们一般是这么做的。
1,代理类一般要持有一个被代理的对象的引用。
2,对于我们不关心的方法,全部委托给被代理的对象处理。
3,自己处理我们关心的方法。
代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
介绍
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例:
优点:
缺点:
使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
注意事项:
实现
我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage
ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image
数据库连接
原本获得数据库连接需要干的事情
数据库连接池
代码实现
1.创建类ConnectionProxy实现java.sql.Connection接口
2.类ConnectionProxy分别实现基础构造方法,close方法
以及要使用的prepareStatement及createStatement
3.实现DataSource,因为数据库连接池只有一个(所以使用单例模式)
4.DataSource具有的特点其他博客写的很清楚了
ConnectionProxy代码
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConnectionProxy implements Connection
//设置连接
private Connection connection;
//使用createStatement的方法,如果返回为空,则在后续使用会空指针异常
@Override
public Statement createStatement() throws SQLException {
return this.connection.createStatement();
}
//构造函数,返回连接
public ConnectionProxy() throws SQLException {
this.connection = DataSource.getInstance().getConnection();
}
//同createSatement
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return this.connection.prepareStatement(sql);
}
//重要的close方法
@Override
public void close() throws
数据库连接池DataSource
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class DataSource
private static String url="jdbc:mysql://127.0.0.1:3306/usertest?useUnicode=true&characterEncoding=utf8";
private static String user="root";
private static String password="xxx";
private static int maxConnection=500;
private static int currentConnection=0;
//LinkedList是非线程安全的所以在操纵LinkedList的时候需要加锁
//需要序列化和反序列化实现单例
private static LinkedList<Connection> connectionList=new LinkedList<Connection>();
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static Connection createNewConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
private DataSource(){
//类初始化不需要加锁
if (connectionList==null||connectionList.size()==0){
for (int i = 0; i < 10; i++) {
try {
connectionList.add(createNewConnection());
} catch (SQLException e) {
e.printStackTrace();
}
currentConnection++;
System.out.println("当前共有连接"+currentConnection);
}
}
}
public Connection getConnection() throws SQLException {
synchronized (DataSource.class){
if (connectionList.size()>0){
System.out.println("有连接可以,从LinkedList中移除一个连接");
return connectionList.remove();
}
if (currentConnection<maxConnection){
try {
return createNewConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
throw new SQLException("无连接可用");
}
public void recoveryConnection(Connection connection){
System.out.println("DataSource获得恢复连接");
synchronized (DataSource.class) {
connectionList.add(connection);
}
}
public static DataSource getInstance(){
return DataSourceInstance.dataSource;
}
private static class DataSourceInstance{
//这里需要写成单例模式 这里使用内部静态类实现单例模式
private static DataSource dataSource = new
写在最后
数据库连接池的实现使用静态代理即可,推荐大家搭配我前面的博客数据库的操作封装使用,相当于自己写了框架Mybatis的感觉,特别爽。