• 实现自己的标准数据库连接池


    对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什 么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性 能的瓶颈。

    对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。

    原理:

    连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用 户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控 制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等

    实现:

    java中实现标准的连接池需要实现DataSource接口,实现类又称为数据源。

    实现类,需要连接数据库并维持一定数量的数据库连接,在getConnection方法中获取Connection连接

    问题是当一个系统用完Connection连接后,DataSource接口中并没有提供release方法去释放Connection连接。(这里的释放并不是真正的连接的释放,而是将连接重新放入连接池中,以保证连接池的数量。试想如果是真正的释放,连接池用几次就没连接了,废了

    这时就需要我们自己去实现将用完的连接重新加入连接池。

    close是Connection接口的实现类中的方法实现类是你用的数据库驱动,当需要对一个已知类的方法进行扩展时,可以通过继承丶包装模式丶动态代理这些方法进行扩展(别想着在别人的jar包里修改close方法,不允许也不能这样做),即需要对Connection接口的实现类中的close方法进行扩展。

    比如你连得mysql,实现类就是mysql的驱动(注意版本不同,数据库不同,实现方式都会有所差异)

    比如我用的mysql-connector-java-5.1.7-bin.jar版本,实现类为com.mysql.jdbc.JDBC4Connection

    考虑继承

    java中实现数据源(就是连接池)的标准接口是DataSource(即要求所有数据源都必须实现该接口),所有java中用到数据源的框架接受的类型都是DataSource类型,如果你实现了自己的标准数据源MyDataSource(实现了DataSource接口),你又写了一个类继承了JDBC4Connection比如叫做MyConnection,你把MyDataSource传入框架,然后调用MyConnection的close方法,这样看似可以?问题是MyDataSource获取的Connection对象MyConnection关闭的Connection对象根本不是同一个对象,所有继承在此行不通。更何况有的驱动版本Connection实现类是final类型不可继承。

    考虑装饰(包装)模式

    装饰模式是完全可以的,利用组合的方式将Connection接口传入装饰者的构造函数里,利用多态将实现类传进来,对close方法进行扩展,其他方法调用实现类中的方法。由于装饰模式前面的博客已经学习过,这里就不在累赘了。

    考虑动态代理(推荐)

    动态代理就是利用反射将Connection中的方法交给代理类去做,这样在调用close方法时可以通过代理类实现对close方法进行扩展

    下面上动态代理解决方案

    标准数据源

    这里在一个properties文件中写数据库相关信息,在实现类中获取数据库连接信息

    package util;
    
    import java.io.InputStream;
    import java.io.PrintWriter;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.LinkedList;
    import java.util.Properties;
    import java.util.logging.Logger;
    import javax.sql.DataSource;
    
    
    public class MyDateSource implements DataSource {
        private static String className;
        private static String url;
        private static String userName;
        private static String password;
        private static LinkedList<Connection> pool = new LinkedList<Connection>();
        static {
            try {
                InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("mypro.properties");
                Properties p = new Properties();
                p.load(is);
                className = p.getProperty("className");
                url = p.getProperty("url");
                userName = p.getProperty("userName");
                password = p.getProperty("password");
                Class.forName(className);
           //维持了10个数据库连接
    for (int i = 0; i < 10; i++) { Connection conn = DriverManager.getConnection(url, userName, password); pool.add(conn); } } catch (Exception e) { e.printStackTrace(); } }   //获取Connection连接 public Connection getConnection() throws SQLException { if(pool.size()>0){ Connection conn= pool.remove();
         //返回Connection的代理对象,并对close方法进行扩展,将连接放回连接池
    return (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(),new Class[]{Connection.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("close".equals(method.getName())){ return pool.add(conn); }else{ return method.invoke(conn, args); } } }); }else{ System.out.println("sorry,server is busy"); } return null; } @Override public PrintWriter getLogWriter() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { // TODO Auto-generated method stub } @Override public void setLoginTimeout(int seconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getLoginTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { // TODO Auto-generated method stub return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { // TODO Auto-generated method stub return false; } @Override public Connection getConnection(String username, String password) throws SQLException { // TODO Auto-generated method stub return null; } }

    这样自己的标准连接池就实现了,在需要用到连接的地方直接使用,用完调用close方法时代理类会将连接放回连接池。

  • 相关阅读:
    线段树优化dp——牛客多校第一场I(好题)
    字符串dp——牛客多校第五场G
    凑出和相等的k组数,玄学结论——hdu6616
    主席树/线段树模拟归并排序+二分答案(好题)——hdu多校第4场08
    思维题+贪心——牛客多校第一场C
    线性基算贡献——19牛客多校第一场H
    俞敏洪语录
    睡眠长短决定寿命!人每天应该睡多少小时
    Java程序员从笨鸟到菜鸟之(三十一)大话设计模式(一)设计模式遵循的七大原则
    spring源码剖析(五)利用AOP实现自定义Spring注解
  • 原文地址:https://www.cnblogs.com/pokid/p/5817625.html
Copyright © 2020-2023  润新知