• 用动态代理实现连接池


    用动态代理实现连接池

    1、用javax.sql.DataSource实现连接池。

           DataSource是标准的数据源。所在连接数据库的工具类,都应该实现这个接口。

    此接口中,只有二个方法:

       这两个方法 ,都是用来获取连接的:

    Connection

    getConnection()
              尝试建立与此 DataSource 对象所表示的数据源的连接。

     Connection

    getConnection(String username, String password)
              尝试建立与此 DataSource 对象所表示的数据源的连接。

          

    4.1、三种实现

    DataSource 接口由驱动程序供应商实现。共有三种类型的实现:

    1. 基本实现 - 生成标准的 Connection 对象
      1. 即这个DataSource中只有一个连接。
    2. 连接池实现 - 生成自动参与连接池的 Connection 对象。此实现与中间层连接池管理器一起使用。
      1. 还需要使用第三方jar包。
    3. 分布式事务实现 - 生成一个 Connection 对象,该对象可用于分布式事务,大多数情况下总是参与连接池。此实现与中间层事务管理器一起使用,大多数情况下总是与连接池管理器一起使用。
      1. 当你连接多个数据库时。要求也可以实现事务。
      2. JTA – Java Transaction Arichi..标准。
        1. javax.sql.XADataSource (接口)

    找一下,哪些类,实现了javax.sql.DataSource接口

    4.1、如何实现

          

    测试使用mysql连接的ds类:

        @Test

        public void test1() throws Exception{

           Class.forName("com.mysql.jdbc.Driver");

           MysqlDataSource ds =

                  new MysqlDataSource();

           ds.setUrl("jdbc:mysql:///oracle?chracterEncoding=UTF8");

           ds.setUser("root");

           ds.setPassword("1234");

           Connection con = ds.getConnection();

           System.err.println("这是第1个:"+con);

           //再测试获取第二个

           con.close();

           Connection con2 = ds.getConnection();

           System.err.println("这是第二个:"+con2);

           System.err.println("--------------------------");

        }

    上面的代码不能使用:

        1:依赖于mysql这个jar包的。

           2:mysq中没有实现池管理。只是每次调用getConnection获取一个新的连接。

    4.3、自己实现标准的连接池

           1:必须要实现javax.sql.DataSource接口。

           2:必须在实现类中,实现池管理.

           3:保证可以回收连接。我就是动态代理实现。

           4:一个项目中,保证只有一个DataSource实例就可以了

    有了ds对象以后,ds就是一个数据源了.

    第一步:开发一个资源文件

    第二步:开发MyDataSource类

    package cn.oracle.utils;

    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.logging.Logger;

    import javax.sql.DataSource;

    /**

     * 不写static

     * @author Administrator 应该让用户提供连接数据库需要信息

     */

    public class MyDataSource implements DataSource {

        // 非静态的

        private LinkedList<Connection> pool = new LinkedList<Connection>();

        // 提供一个构造方法

        // 在构造中,让用提供四个

        public MyDataSource(String driver, String url, String user, String pwd)

               throws Exception {

           this(driver, url, user, pwd, 1);

        }

        public MyDataSource(String driver, String url, String user, String pwd,

               int pooSize) throws Exception {

           Class.forName(driver);

           for(int i=0;i<pooSize;i++){

               Connection con = DriverManager.getConnection(url,user,pwd);

               //将三个原生的conn放到

               pool.addLast(con);

           }

        }

        @Override

        public Connection getConnection() throws SQLException {

           synchronized (pool) {

               if(pool.size()==0){

                  try {

                      pool.wait();

                  } catch (InterruptedException e) {

                      e.printStackTrace();

                  }

                  return getConnection();

               }else{

                  final Connection con = pool.removeFirst();

                  Object obj =

                         Proxy.newProxyInstance(MyDataSource.class.getClassLoader(),

                                new Class[]{Connection.class},

                                new InvocationHandler() {

                                    @Override

                                    public Object invoke(Object proxy, Method method, Object[] args)

                                           throws Throwable {

                                       if(method.getName().equals("close")){

                                           synchronized (pool) {

                                              pool.add(con);

                                              pool.notify();

                                              return null;

                                           }

                                       }else{

                                           //放行,调用原生的

                                           return method.invoke(con, args);

                                       }

                                    }

                                });

                  System.err.println("size si:"+pool.size());

                  return (Connection) obj;

               }

           }

        }

        //还有些方法就不用实现了

    }

    实现一个工具类,对MyDataSource实现工厂方式获取:

    package cn.oracle.utils;

    import java.sql.Connection;

    import java.util.Properties;

    import javax.sql.DataSource;

    /**

     */

    public class DataSourceUtils {

        private static DataSource ds;

        static {

           try {

               Properties p = new Properties();

               p.load(ClassLoader.getSystemResourceAsStream("jdbc.properties"));

               ds = new MyDataSource(p.getProperty("driver"),

                      p.getProperty("url"), p.getProperty("user"),

                      p.getProperty("password"), Integer.parseInt(p

                             .getProperty("size")));

     

           } catch (Exception e) {

               throw new RuntimeException(e);

           }

        }

        //提供一个返回一个ds的方法

        public static DataSource getDatasSource(){

           return ds;

        }

        //还可以提供一个方法

        public static Connection getCon() throws Exception{

           return ds.getConnection();

        }

    }

    代码结构如下:

    测试如下:

    5、使用第三方连接池

           DBCP

           C3p0

           研究它们是用什么实现回收连接的?是包装还是代理。

    5.1、DBCP

           DataBase Connection Pool

    使用dbcp连接数据库

     创建dbcp数据源:

    \

    第一步:导入dbcpjar包及它的依赖包

    第二步:dbcp核心

           必须是DataSource的子类

    用BasicDataSouce连接数据库:

    直接在类中声明:

        BasicDataSource ds =

                  new BasicDataSource();

           //找set

           ds.setDriverClassName("com.mysql.jdbc.Driver");

           ds.setUsername("root");

           ds.setPassword("1234");

           ds.setUrl("jdbc:mysql:///oracle?characterEncoding=UTF8");

           //看有几个连接

           ds.setInitialSize(3);//设置开始时有几个连接

           ds.setMaxActive(3);//设置最多有几个连接

    或是通过配置文件读取:

        、

    还是像

    开发获取dbcp数据源的工具类:

    package cn.oracle.utils;

    import java.sql.Connection;

    import java.util.Properties;

    import javax.sql.DataSource;

    import org.apache.commons.dbcp.BasicDataSource;

    import org.apache.commons.dbcp.BasicDataSourceFactory;

    public class DBCPUtils {

        private static DataSource ds;

        static {

           try {

               Properties p = new Properties();

               p.load(ClassLoader.getSystemResourceAsStream("bb.properties"));

               ds = BasicDataSourceFactory.createDataSource(p);

           } catch (Exception e) {

     

           }

        }

        public static DataSource getDs(){

           return ds;

        }

        public static Connection getCon() throws Exception{

           return ds.getConnection();

        }

    }



    包装与代理:

           由于包装就只两个实例类在进行交互。

           反射比较慢。

          

          

    6、元数据分析

          

          

           只通过一个connection可以分析,目前数据库的所有信息:

                  版本

                  连接是什么数据库

            驱动器版本

            获取这个数据库中有多少表.

    6.1、用DataBaseMetaData分析数据库的连接

               /**

         * 用元数据信息分析某个连接的数据库中有多少表

         */

        @Test

        public void getTables() throws Exception{

           Connection con = DBCPUtils.getConnection();

           DatabaseMetaData db = con.getMetaData();

           //获取表的所有表名

           //第一个参数与第二个参数是是指数据库是什么

           //第三个参数你查找表名,

           //找什么对象

           ResultSet rs = db.getTables("mysql","mysql",null,new String[]{"TABLE"});

           //显示表名

           while(rs.next()){

               String tname = rs.getString("TABLE_NAME");

               System.err.println(tname);

           }

        }

    6.2、分析结果集的信息

           通过一个查询获取表中列,字段名类型 信息

     

           请显示出mysql库中的user表的所有信息

        @Test

        public void testTable() throws Exception{

           String sql = "select host,db,user from mysql.db";

           //获取连接

           Connection con = DBCPUtils.getConnection();

           Statement st = con.createStatement();

           //先获取到结果集

           ResultSet rs = st.executeQuery(sql);

           //获取结果集的元信息

           ResultSetMetaData rsmd = rs.getMetaData();

           //获取这个结果一共有几列

           int cols = rsmd.getColumnCount();//5[微软用户1] 

           //获取列名

           for(int i=1;i<=cols;i++){

               String cName = rsmd.getColumnName(i);[微软用户2] 

               System.err.print(cName+"\t\t");

           }

           System.err.println();

           while(rs.next()){

               //一行数据

               for(int i=1;i<=cols;i++){

                  String data = rs.getString(i);

                  System.err.print(data+"\t\t");

               }

               System.err.println();

           }

        }

  • 相关阅读:
    【转】c++继承中的内存布局
    Google 开源项目风格指南
    常见面试题
    PHP7.1中使用openssl替换mcrypt
    phpunit实践笔记
    PHP的错误处理
    CI的扩展机制
    #CI的MVC实现
    Laravel中的队列处理
    laravel的模块化是如何实现的
  • 原文地址:https://www.cnblogs.com/ljhoracle/p/3032082.html
Copyright © 2020-2023  润新知