数据库连接池(数据源)1


一、数据库连接池原理

            



            
            例:
            ************************************************************************************           
            public class SimpleConnectionPool {


                    private static String driverClassName;
                    private static String url;
                    private static String user;
                    private static String password;
                    // 创建一个集合作为存储连接的池,用来存储数据库的连接  
                    private static LinkedList<Connection> pool = new LinkedList<Connection>();
                    
                    static{
                            try {
                                    InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
                                    Properties props = new Properties();
                                    props.load(in);
                                    driverClassName = props.getProperty("driverClassName");
                                    url = props.getProperty("url");
                                    user = props.getProperty("user");
                                    password = props.getProperty("password");
                                    Class.forName(driverClassName);          
                                                            
                                    // 初始化10个连接到池中
                                    for (int i = 0; i < 10; i++) {
                                            Connection conn = DriverManager.getConnection(url, user, password);
                                            pool.add(conn);
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }


                    // 从数据库连接池中获取连接 注:为了避免多线程均从第一个拿,所以要加同步
                    public synchronized static Connection getConnection(){
                            if(pool.size()>0){
                                    // 从池中拿到连接,并从池中删掉该连接
                                    Connection conn = pool.remove();                                             
                                    return conn;
                            }else{
                                    System.out.println("对不起,服务器繁忙");
                                    return null;
                            }
                    }
                      
                    // 将连接放回数据库连接池中
                    public static void release(Connection conn){
                            pool.add(conn);          
                    }
                
            }
            ************************************************************************************
            // 模拟使用数据库连接池(数据源)
            public class SimpleConnectionPoolClient {
                    public static void main(String[] args) {
                            // 创建连接
                            Connection c1 = SimpleConnectionPool.getConnection();
                            // 省略一些使用c1操作DAO的代码
                            Connection c2 = SimpleConnectionPool.getConnection();
                            // 省略一些使用c2操作DAO的代码
                            Connection c3 = SimpleConnectionPool.getConnection();
                            // 省略一些使用c3操作DAO的代码
                            
                            // 释放连接
                            SimpleConnectionPool.release(c2);
                            SimpleConnectionPool.release(c3);
                            SimpleConnectionPool.release(c1);
                    }
            }
            ************************************************************************************
            




二、编写标准的数据库连接池
     6.1 实现了javax.sql.DataSource接口的才是标准的数据库连接池,按照字面意思,一般称之为数据源。
            
     6.2  创建一个标准的数据源
            **********************************************************************************************
            
            public class MyDataSource implements DataSource {


                    private static String driverClassName;
                    private static String url;
                    private static String user;
                    private static String password;
                    private static LinkedList<Connection> pool = new LinkedList<Connection>();
                    
                    static{
                            try {
                                    InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
                                    Properties props = new Properties();
                                    props.load(in);
                                    driverClassName = props.getProperty("driverClassName");
                                    url = props.getProperty("url");
                                    user = props.getProperty("user");
                                    password = props.getProperty("password");
                                    Class.forName(driverClassName);
                                    // 初始化10个连接到连接池中
                                    for(int i=0; i<10; i++){
                                            Connection conn = DriverManager.getConnection(url, user, password);
                                            pool.add(conn);
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
                    
                    // 从池中获取一个连接
                    @Override
                    public synchronized Connection getConnection() throws SQLException {
                            if(pool.size()>0){
                                    Connection conn = pool.remove();
                                    //  方式2-Ⅰ: 包装设计模式复写close方法
                              // MyConnection mconn = new MyConnection(conn, pool);
                                    //  方式2-Ⅱ: 通过继承 默认适配器的包装设计模式复写close方法
                                    MyConnection1 mconn = new MyConnection1(conn, pool);
                                    return mconn;
                            }else{
                                    throw new RuntimeException("对不起,服务器繁忙");
                            }
                    }


                    @Override
                    此处省略一些接口中需要覆盖的方法


            }
            
            **********************************************************************************************
            
            public class MyDataSourceClient {
                    // private static DataSource ds = new MyDataSource();
                    //  方式3: 使用动态代理方式创建的数据源来拦截close方法             
                    private static DataSource1 ds = new MyDataSource1();
                    
                    public static void main(String[] args) {
                            Connection conn = null;
                            PreparedStatement stmt = null;
                            try{
                                    conn = ds.getConnection();
                                    // 利用conn做一些dao操作
                                    conn.createStatement();
                            }catch(Exception e){
                                    e.printStackTrace();
                            }finally{
                                    if(stmt!=null){
                                            try {
                                                    stmt.close();
                                            } catch (SQLException e) {
                                                    e.printStackTrace();
                                            }
                                            stmt = null;
                                    }
                                    if(conn!=null){
                                            try {
                                                    conn.close();  // 该方法应该做到:不要关闭连接,而应该还回池中,应该复写该方法
                                            } catch (SQLException e) {
                                                    e.printStackTrace();
                                            }
                                            conn = null;
                                    }
                            }                     
                    }
            }
            
            **********************************************************************************************




      6.3 引发的问题:  conn.close() // 该方法应该做到:不要关闭连接,而应该还回池中,应该复写该方法           
                               
            对于一个已知类的某个方法进行功能上的改变有以下三种方式: 
                        1、定义子类,扩展父类的某个功能。(此处行不通)
                        2、利用包装设计模式改写原有的类的功能
                                方式2-Ⅰ:包装设计模式   
                                        a、编写一个类实现与被改写类(com.mysql.jdbc.Connection)相同的接口
                                        b、定义一个引用,记住被改写类的实例
                                        c、定义构造方法,传入被改写类的实例
                                        d、对于要改写的方法,改写即可
                                        e、对于不需要改写的方法,调用原有的对象的对应方法        
                                                                             
                                方式2-Ⅱ:默认适配器设计模式
                                        a.编写一个类,继承默认适配器
                                        b.定义一个引用,记住被改写类的实例
                                        c.定义构造方法,传入被改写类的实例
                                        d.对于要改写的方法,改写即可
                          
                        3、动态代理:  基于接口的动态代理(最佳解决方案)
                                java.lang.reflect.Proxy
                                static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)                               
                                作用:返回代理类的实例
                                参数:
                                    loader:类加载器,一般与被代理对象使用同一个
                                    interfaces:被代理对象所实现的接口
                                    h:怎么代理
                                    
                               Object invoke(Object proxy, Method method, Object[] args) :调用原有类的任何方法,都会经过此方法。
                                   
            **********************************************************************************************
            
            方式2-Ⅰ:包装设计模式改写com.mysql.jdbc.Connect中的close访法,在调用时,不是关闭连接,而是返回池中
            public class MyConnection implements Connection{
                    private Connection conn; // 引用被改写对象
                    private LinkedList<Connection> pool;                 
                    public MyConnection(Connection conn,LinkedList<Connection> pool){
                    // 通过构造方法注入需要的对象: 依赖注入: spring框架的核心
                            this.conn = conn;
                            this.pool = pool;
                    }
                    
                    @Override
                    public void close() throws SQLException {
                            pool.add(conn);
                    }


                    @Override
                    public void clearWarnings() throws SQLException {
                            conn.clearWarnings();
                    }
                    
                    @Override
                   此处省略一系列的接口中被覆盖的方法


            }
            在上面的获取连接,将被包装的类换为包装类:MyConnection mconn = new MyConnection(conn, pool);
            
            **********************************************************************************************
            
            方式2-Ⅱ: 通过继承默认适配器的包装设计模式改写com.mysql.jdbc.Connect中的close访法
           
             // 全部调用原有对象的原有方法,没有做任何功能上的改动
            //  此类便是一个默认适配器   再设置一个MyConnection1继承该类,并覆盖close方法
            public class ConnectionWrapper implements Connection {  // 包装类
                  private Connection conn;
                  public ConnectionWrapper(Connection conn){
                          this.conn = conn;
                  }
                  @Override
                  public void clearWarnings() throws SQLException {
                            conn.clearWarnings();
                  }
                  此处省略一系列的覆盖的方法;
             }
             // 继承默认适配器类,复写close方法
             public class MyConnection1 extends ConnectionWrapper {
                    private Connection conn;
                    private LinkedList<Connection> pool;             
                    public MyConnection1(Connection conn, LinkedList<Connection> pool) {
                            super(conn);
                            this.pool = pool;
                    }
                    @Override
                    public void close() throws SQLException {
                            pool.add(conn);
                    }          
            }
            在上面的获取连接,将被包装的类换为包装类:MyConnection1 mconn = new MyConnection1(conn, pool);
            
            **********************************************************************************************
            方式3:  基于接口的动态代理(最佳方案)
            
            public class MyDataSource1 implements DataSource {
                    private static String driverClassName;
                    private static String url;
                    private static String user;
                    private static String password;
                    private static LinkedList<Connection> pool = new LinkedList<Connection>();
                    
                    static{
                            try {
                                    InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
                                    Properties props = new Properties();
                                    props.load(in);
                                    driverClassName = props.getProperty("driverClassName");
                                    url = props.getProperty("url");
                                    user = props.getProperty("user");
                                    password = props.getProperty("password");
                                    Class.forName(driverClassName);
                                    // 初始化10个连接到连接池中
                                    for(int i=0; i<10; i++){
                                            Connection conn = DriverManager.getConnection(url, user, password);
                                            pool.add(conn);
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
                    
                    // 从池中获取一个连接
                    @Override
                    public Connection getConnection() throws SQLException {
                            if(pool.size()>0){
                                    final Connection conn = pool.remove(); // 原有对象
                                    // 返回动态代理对象
                                    return (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(), 
                                                  conn.getClass().getInterfaces(), new InvocationHandler(){   
                                      @Override //注: 调用Conncection的任何方法都会经过该方法
                                      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{
                                    throw new RuntimeException("对不起,服务器繁忙");
                            }
                    }


                    @Override
                    此处省略一系列的覆盖方法
            }          

            注:  然后调用数据源的时候调用该数据源即可;

            **********************************************************************************************





 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值