1.数据库连接池
什么是数据库连接池
简单来说:数据库连接池就是提供连接的。。。
为什么我们要使用数据库连接池
- 数据库的连接的建立和关闭是非常消耗资源的
- 频繁地打开、关闭连接造成系统性能低下
编写连接池
- 编写连接池需实现java.sql.DataSource接口
- 创建批量的Connection用LinkedList保存【既然是个池,当然用集合保存、、LinkedList底层是链表,对增删性能较好】
- 实现getConnetion(),让getConnection()每次调用,都是在LinkedList中取一个Connection返回给用户
- 调用Connection.close()方法,Connction返回给LinkedList
private static LinkedList<Connection> list = new LinkedList<>(); //获取连接只需要一次就够了,所以用static代码块 static { //读取文件配置 InputStream inputStream = Demo1.class.getClassLoader().getResourceAsStream("db.properties"); Properties properties = new Properties(); try { properties.load(inputStream); String url = properties.getProperty("url"); String username = properties.getProperty("username"); String driver = properties.getProperty("driver"); String password = properties.getProperty("password"); //加载驱动 Class.forName(driver); //获取多个连接,保存在LinkedList集合中 for (int i = 0; i < 10; i++) { Connection connection = DriverManager.getConnection(url, username, password); list.add(connection); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } //重写Connection方法,用户获取连接应该从LinkedList中给他 @Override public Connection getConnection() throws SQLException { System.out.println(list.size()); System.out.println(list); //先判断LinkedList是否存在连接 return list.size() > 0 ? list.removeFirst() : null; }
我们已经完成前三步了,现在问题来了。我们调用Conncetion.close()方法,是把数据库的物理连接关掉,而不是返回给LinkedList的
解决思路:
- 写一个Connection子类,覆盖close()方法
- 写一个Connection包装类,增强close()方法
- 用动态代理,返回一个代理对象出去,拦截close()方法的调用,对close()增强
分析第一个思路:
- Connection是通过数据库驱动加载的,保存了数据的信息。写一个子类Connection,new出对象,子类的Connction无法直接继承父类的数据信息,也就是说子类的Connection是无法连接数据库的,更别谈覆盖close()方法了。
分析第二个思路:
- 写一个Connection包装类。
- 写一个类,实现与被增强对象的相同接口【Connection接口】
- 定义一个变量,指向被增强的对象
- 定义构造方法,接收被增强对象
- 覆盖想增强的方法
- 对于不想增强的方法,直接调用被增强对象的方法
- 这个思路本身是没什么毛病的,就是实现接口时,方法太多了!,所以我们也不使用此方法
分析第三个思路代码实现:
@Override public Connection getConnection() throws SQLException { if (list.size() > 0) { final Connection connection = list.removeFirst(); //看看池的大小 System.out.println(list.size()); //返回一个动态代理对象 return (Connection) Proxy.newProxyInstance(Demo1.class.getClassLoader(), connection.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果不是调用close方法,就按照正常的来调用 if (!method.getName().equals("close")) { method.invoke(connection, args); } else { //进到这里来,说明调用的是close方法 list.add(connection); //再看看池的大小 System.out.println(list.size()); } return null; } }); } return null; }
我们上面已经能够简单编写一个线程池了。下面我们来使用一下开源数据库连接池