• JDBC学习笔记(三)


      获取数据库的元信息metadata,里面有数据库特性的描述信息,如是否支持事务,是否支持批处理等。

    Connection conn = DriverManager.getConnection(url, userName,passwrod); 
    DatabaseMetaData md = conn,getMetaData();
    System.out.println(md.supportTransactions());

          还可以获取参数的metadata:

          PreparedStatement ps = conn.prepareStatement(sql);

          ParamterMetaData pm = ps.getParamterMetaData();

         还可以获取返回的结果集中的metadata,用于将结果封装为需求的对象如Map,List等:

         ResultSet rs = ps.executeQuery();
         ResultSetMetaData meta = rs.getMetaData();

      

         class的无参数的newInstance方法要求类有一个无参数的构造方法。

         Constructor con = class.getConstructor(String.class);     //取得对象的参数为String的构造方法,参数是可变长度的数组

       Object  obj = con.newInstance("test");         //参数是可变长度的数组

      Method [] ms = object.getClass.getDeclaredMethods();     //找到类中的所有方法,包括私有方法,但不包括父类方法

           Method [] ms = object.getClass.getMethods();     //找到类及父类方法中的所有方法,但不包括私有方法

       

       Java类库中有三个类直接支持代理模式:Proxy,InvocationHandler和Method。

         下面是在List加上代理,在添加元素的前后打印一些信息。

    public class VectorProxy implements InvocationHandler{
    
        private Object proxyobj;
    
        public VectorProxy(Object obj){
    
            proxyobj = obj;
    
        }
    
     
    
        public static Object factory(Object obj){
    
            Class cls = obj.getClass();
    
            return Proxy.newProxyInstance( cls.getClassLoader(),
    
                cls.getInterfaces(),
    
                new VectorProxy(obj) );
    
        }
    
     
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    
            System.out.println("before calling " + method);
    
     
    
            if (args != null){
    
                for (int i=0; i<args.length; i++){
    
                    System.out.println(args[i] + "");
    
                }
    
            }
    
     
    
            Object o = method.invoke(proxyobj, args);
    
     
    
            System.out.println("after calling " + method);
    
     
    
            return o;
    
        }
    
     
    
        public static void main(String[] args){
    
            List v = null;
    
            v = (List) factory(new Vector(10));
    
            v.add("New");
    
            v.add("York");
    
        }
    
    }

      打印出的信息如下:

    before calling public abstract boolean java.util.List.add(java.lang.Object)
    
    New
    
    after calling public abstract boolean java.util.List.add(java.lang.Object)
    
    before calling public abstract boolean java.util.List.add(java.lang.Object)
    
    York
    
    after calling public abstract boolean java.util.List.add(java.lang.Object)

       代理模式需要一个原始类的实例,InvocationHandler中invoke方法实际调用的是原始类的实例,需要仿照着一个实例在内存中动态地生成字节码。因为方法除非是静态方法,否则都是要和实例来绑定使用的。

      利用代理模式,如果希望java.sql.Connection的close方法不是去关掉真正的数据库连接而是将连接放回到连接池中,可以使用下面的代码:

    public class ConnectionProxy implements InvocationHandler{
    
        private java.sql.Connection wrappedConnection;
    
        private java.sql.Connection realConn;
    
        private DataSource dataSource;
    
        public ConnectionProxy(DataSource dataSource ){
               this.dataSource = dataSource;
        }
    
    
        public static java.sql.Connection bind(java.sql.Connection conn){
            this.realConn = conn;
    
            Class cls = conn.getClass();
        
           wrappedConnection =  Proxy.newProxyInstance( cls.getClassLoader(),
    
                   /*cls.getInterfaces()*/new class[]{java.sql.Connection.class},this); //这里需要继承自java.sql.Connection接口,否则创建出的连接在连接池添加,删除时有问题
    return wrappedConnection; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ if (method.getName().equals("close")){ this.dataSource.connectionsPool.addLast(wrappedConnection);Q } Object o = method.invokerealConn;args); return o; } }

       DataSource类中产生connection时就换为ConnectionProxy即可。

    private Connection createConnection(){
        java.sql.Connection conn = DriverManager.getConnection(url,user,password);
        ConnectionProxy proxy = new ConnectionProxy(this);
        return proxy.bind(conn );
    
    }

      

      通过数据源DataSource中的连接池获取的Connection都是包装后的Connection,已经修改了close方法,不是简单的关闭连接,而是要再放回连接池中。

       

      连接池一般会要求提供一个配置文件,基本的配置项包括:初始连接数,最大连接数,最大、最小空闲连接数等。下面的是一个Durid数据库连接池的配置文件: 

    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    
            <property name="url" value="${jdbc_url}" />
    
            <property name="username" value="${jdbc_username}" />
    
            <property name="password" value="${jdbc_password}" />
    
     
    
            <!-- 初始化连接大小 -->
    
            <property name="initialSize" value="0" />
    
            <!-- 连接池最大使用连接数量 -->
    
            <property name="maxActive" value="20" />
    
            <!-- 连接池最大空闲 -->
    
            <property name="maxIdle" value="20" />
    
            <!-- 连接池最小空闲 -->
    
            <property name="minIdle" value="0" />
    
            <!-- 获取连接最大等待时间 -->
    
            <property name="maxWait" value="60000" />
    
     
    
            <!-- <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> -->
    
     
    
            <property name="validationQuery" value="${validationQuery}" />
    
            <property name="testOnBorrow" value="false" />
    
            <property name="testOnReturn" value="false" />
    
            <property name="testWhileIdle" value="true" />
    
     
    
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    
            <property name="timeBetweenEvictionRunsMillis" value="60000" />
    
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    
            <property name="minEvictableIdleTimeMillis" value="25200000" />
    
     
    
            <!-- 打开removeAbandoned功能 -->
    
            <property name="removeAbandoned" value="true" />
    
            <!-- 1800秒,也就是30分钟 -->
    
            <property name="removeAbandonedTimeout" value="1800" />
    
            <!-- 关闭abanded连接时输出错误日志 -->
    
            <property name="logAbandoned" value="true" />
    
     
    
            <!-- 监控数据库 -->
    
            <!-- <property name="filters" value="stat" /> -->
    
            <property name="filters" value="mergeStat" />
    
        </bean>

       上面将配置信息直接写到程序中的方法并不好,可以写成配置文件druiddb.xml,去从配置文件中来读取配置。

    driverClassName = com.mysql.jdbc.Driver
    url =com.mysql.jdbc.Driver
    uer = root
    password = OSSDB123
    initialSize =5

        再修改上面的DruidManager类,使之从配置文件中加载参数:

    Properties p = new Properties();
    
    InputStream is = DuridManager,class.getClassLoader().loadResourceAsStream("duriddb.xml");
    
    p.load(is);
    
    dataSource = new DruidDataSource(p);

       连接池的connection也是包装后的connection,需要改写close方法。

         

  • 相关阅读:
    [工作中的设计模式]中介模式模式Mediator
    [工作中的设计模式]责任链模式chain
    [工作中的设计模式]迭代子模式Iterator
    [工作中的设计模式]组合模式compnent
    TI IPNC Web网页之流程分析
    TI IPNC Web网页之GoDB开发环境
    安装ubuntu时将boot目录单独挂载的意义
    ubuntu添加自定义vga输出分辨率
    GCC编译默认的头文件搜索路径
    设置搜狗输入法在任何时候按左右两侧的shift激活
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/4102605.html
Copyright © 2020-2023  润新知