自建连接池,通过动态代理增强getConnection()方法,使其调用用close()方法时具有返回连接的功能
一、JDBC
1.概述与原理
JDBC(Java DataBase Connectivity):就是Java数据库连接,简单说就是封装了java语言操作不同据库(例如:mysql,oracle、sqlServer等数据库)的接口,各个数据库厂商实现这个接口。因此java语言可以通过JDBC操作各个数据库。
JDBC工作原理
sun公司为了简化和统一java连接数据库,定义的一套规范(类,接口),并提供连接数据库的协议标准

2.API介绍
1. DriverManager:驱动管理器
+ 注册驱动:public static void registerDriver(Driver driver);
+ 获得连接: public static Connection getConnection(String url,String user,String password);
2. Connection: 代表连接对象
+ 创建执行sql语句对象:public Statement createStatement();
+ 创建预编译sql语句对象:PreparedStatement prepareStatement(String sql);
+ 事务操作:
+ void setAutoCommit(boolean autoCommit); false--手动开启事务(start transaction)
+ void commit();提交事务(commit)
+ void rollback();回滚事务(rollback)
3. Statement: 执行sql语句对象
+ 执行查询 ResultSet executeQuery(String sql); 返回结果集
+ 执行增删改 int excuteUpdate(String sql); 返回受影响的行数
4. ResultSet: 结果集
+ boolen next(); 每调用一次, 光标就向下移动一行; 这个行有数据, 返回true; 没有数据, 返回false
+ get类型(String 列名); 根据列名 获得当前列的数据
二、连接池
1.概述与原理
为什么要使用连接池:
Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了(close).每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.
程序初始化的时候,**初始化多个连接,将多个连接放入到池(集合)中**.每次获取的时候,都可以直接**从连接池中进行获取.使用结束以后,将连接归还到池中.**
连接池原理:
1. 程序一开始就创建一定数量的连接,放在一个容器(集合)中,这个容器称为连接池。
2. 使用的时候直接从连接池中取一个已经创建好的连接对象, 使用完成之后 归还到池子
3. 如果池子里面的连接使用完了, 还有程序需要使用连接, 先等待一段时间(eg: 3s), 如果在这段时间之内有连接归还, 就拿去使用; 如果还没有连接归还, 新创建一个, 但是新创建的这一个不会归还了(销毁)
4. 集合选择LinkedList
增删比较快
LinkedList里面的removeFirst()和addLast()方法和连接池的原理吻合
三、动态代理
1.概述与原理
1.Java.lang.reflect.Proxy:java中负责为实现指定接口的类对象,可以为任意的接口实现类对象做代理。
2.动态代理可以为被代理对象的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强,而不需要专门定义一个代理类。
3.动态代理与代理模式原理是一样,只是没有具体的代理类,底层通过反射机制生成代理对象,无需程序员手工编写它的源代码。
4.动态代理的获取:jdk提供一个Proxy类,为实现指定接口的对象直接生成代理对象
5.动态代理同时也提高了开发效率。
缺点:只能针对接口的实现类做代理对象,普通类是不能做代理对象的。
2.API介绍

四、动态代理增强getConnection()方法
1.原因:
自建连接池为什么要去增强getConnection()方法,当连接释放资源时调用的是Connection接口中的close()方法,而我们的连接是通过DataSource接口中的getConnection()方法获取,其中并没有close()方法且关闭后没有返回连接的功能。要使我们通过自建的连接池获得的连接具有关闭资源的方法且关闭之后要返回连接,就需要通过动态代理模式增强getConnection()方法返回增强的连接,该增强的连接实现了Connection接口具有close()方法 通过pool.addLast(connection)归还连接
2.代码思路与实现
自定义MyDataSource连接池类实现DataSouce接口(为了增强getConnection方法)
定义Linkedlist集合存储连接,因为LinkedList增删比较快且LinkedList里面的removeFirst()和addLast()方法和连接池的原理吻合,使用public static修饰。
在静态代码块中创建连接池
通过读取Properties对象读取properties文件得到创建驱动和获取连接的参数
// 创建Properties对象
Properties pro = new Properties();
// 加载配置文件
// 通过类加载器返回的流默认路径是src
InputStream is = MyDataSource.class.getClassLoader().getResourceAsStream("me.properties");
pro.load(is);
// 获取配置文件中的数据
mydriverclass = pro.getProperty("mydriverclass");
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
// 注册驱动
Class.forName(mydriverclass);

注册驱动
循环创建connection对象加入list集合
通过动态代理对getConnection()方法增强,判断是否是增强的方法是则归还连接,不是则通过反射机制调用方法。
整体代码如下
public class MyDataSource implements DataSource {
//- 在连接池类中,定义一个LinkedList集合成员变量(表示连接池)
private static LinkedList<Connection> pool = new LinkedList<>();
//- 在连接池类的静态代码块中,创建固定数量个连接,并存储到LinkedList集合中
static {
String username = null;
String password = null;
String url = null;
String mydriverclass = null;
try {
// 创建Properties对象
Properties pro = new Properties();
// 加载配置文件
// 通过类加载器返回的流默认路径是src
InputStream is = MyDataSource.class.getClassLoader().getResourceAsStream("me.properties");
pro.load(is);
// 获取配置文件中的数据
mydriverclass = pro.getProperty("mydriverclass");
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
// 注册驱动
Class.forName(mydriverclass);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 5; i++) {
try {
// 创建连接
Connection connection = DriverManager.getConnection(url, username, password);
// 把连接添加到连接池中
pool.add(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public Connection getConnection() throws SQLException {
//- 在连接池类中定义一个公共的非静态的成员方法,用来获取连接(删除集合中第一个元素)
// 被代理对象----没有增强的连接对象
Connection connection = pool.removeFirst();
// 代理对象----增强后的连接对象
// 获取被代理类的类加载器
ClassLoader classLoader = connection.getClass().getClassLoader();
// 获取被代理类实现的所有接口的字节码对象
Class<?>[] interfaces = connection.getClass().getInterfaces();
// 创建事件处理接口
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// 判断是否是增强的方法
if ("close".equals(method.getName())) {
// 增强---归还连接
pool.addLast(connection);
return null;
} else {
// 不增强---通过反射调用被代理类中同名的方法
Object res = method.invoke(connection, objects);
return res;
}
}
};
// 直接生成代理对象
Connection proxy = (Connection) Proxy.newProxyInstance(classLoader, interfaces, h);
// 返回代理对象
return proxy;
}
//- 在连接池类中定义一个公共的非静态方法用来获取连接池中的连接数量
public int size() {
return pool.size();
}
@Override
public Connection getConnection(String s, String s1) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter printWriter) throws SQLException {
}
@Override
public void setLoginTimeout(int i) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> aClass) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> aClass) throws SQLException {
return false;
}
}
3测试
public class Test {
public static void main(String[] args) throws Exception{
MyDataSource myDataSource = new MyDataSource();
Connection connection = myDataSource.getConnection();
String sql="select * from user where id = ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1,1);
ResultSet resultSet = ps.executeQuery();
User user=null;
while(resultSet.next()){
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
String nickname = resultSet.getString("nickname");
user=new User(id,username,password,nickname);
}
System.out.println("连接池中连接的数量:"+myDataSource.size());// 4
System.out.println("user:" + user);
//- 释放资源
resultSet.close();
ps.close();
connection.close();// 销毁变成归还
//dataSource.addBack(connection);
System.out.println("连接池中连接的数量:"+myDataSource.size());// 5
}
}
运行结果


用完之后释放了资源且归还了连接。
更多推荐



所有评论(0)