• 【Java EE 学习 17 上】【dbutils和回调函数】


    一、dbutils的核心就是回调函数,可以说如果没有回调函数的思想,dbutils是不可能被开发出来的。

      对于dbutils中的QuryRunner类,向该类的query方法提供不同的参数,可以得到不同类型的返回值类型,但是该方法并非是重载方法,这里借助回调函数和泛型可以实现和重载方法相同的效果,而且灵活性更高。

    二、简单回调函数结构。

      1.首先需要一个处理句柄的顶级接口,这是回调规范。

    interface RunnerHandler<T>
    {
        T handler(String str);
    }

      2.需要一个类似于QueryRunner类的运行类,这是调用类

    class Runner
    {
        public <T> T query(String str,RunnerHandler<T> rh)
        {
            return rh.handler(str);
        }
    }

      3.一个测试类。

    public class CallBackDemo {
        public static void main(String args[])
        {
            Runner run=new Runner();
            run.query("你好",new RunnerHandler<List<Map<String,Object>>>(){
                @Override
                public List<Map<String, Object>> handler(String str) {
                    System.out.println(str);
                    return null;
                }
            });
        }
    }

      4.运行结果

    你好

      5.疑问:废了这么大的劲,为什么不直接在测试代码中进行打印输出呢?

        实际上打印输出在这里只是一个举例,能干的事情不仅仅是打印输出,虽然只是一个简单的打印输出,但是已经能够在一定程度上说明回调函数是怎么回事儿了。

    三、模拟dbutils

      0.c3p0数据库连接池工具。

     1 package day17.regular.utils;
     2 /**
     3  * 使用c3p0创建的连接池。
     4  */
     5 import java.sql.Connection;
     6 import java.sql.SQLException;
     7 
     8 import javax.sql.DataSource;
     9 
    10 import com.mchange.v2.c3p0.ComboPooledDataSource;
    11 
    12 public class DataSourceUtils_C3P0 {
    13     private static DataSource ds=null;
    14     static{
    15         ds=new ComboPooledDataSource("namedconfig");
    16     }
    17     public static Connection getConnection(){
    18         Connection conn=null;
    19         try {
    20             conn=ds.getConnection();
    21         } catch (SQLException e) {
    22             e.printStackTrace();
    23         }
    24         return conn;
    25     }
    26     public static DataSource getDataSource(){
    27         return ds;
    28     }
    29 }
    DataSourceUtils_C3P0.java
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <c3p0-config>
     3     <!-- 默认配置,只可以出现一次 -->
     4     <default-config>
     5         <!-- 连接超时设置30秒 -->
     6         <property name="checkoutTimeout">30000</property>
     7         <!-- 30秒检查一次connection的空闲 -->
     8         <property name="idleConnectionTestPeriod">30</property>
     9         <!--初始化的池大小 -->
    10         <property name="initialPoolSize">2</property>
    11         <!-- 最多的一个connection空闲时间 -->
    12         <property name="maxIdleTime">30</property>
    13         <!-- 最多可以有多少个连接connection -->
    14         <property name="maxPoolSize">10</property>
    15         <!-- 最少的池中有几个连接 -->
    16         <property name="minPoolSize">2</property>
    17         <!-- 批处理的语句-->
    18         <property name="maxStatements">50</property>
    19         <!-- 每次增长几个连接 -->
    20         <property name="acquireIncrement">3</property>
    21         <property name="driverClass">com.mysql.jdbc.Driver</property>
    22         <property name="jdbcUrl">
    23             <![CDATA[jdbc:mysql://10.6.112.200:3306/test?useUnicode=true&characterEncoding=UTF-8]]>
    24         </property>
    25         <property name="user">root</property>
    26         <property name="password">5a6f38</property>
    27     </default-config> 
    28     
    29     <named-config name="namedconfig">
    30         <!-- 连接超时设置30秒 -->
    31         <property name="checkoutTimeout">30000</property>
    32         <!-- 30秒检查一次connection的空闲 -->
    33         <property name="idleConnectionTestPeriod">30</property>
    34         <!--初始化的池大小 -->
    35         <property name="initialPoolSize">2</property>
    36         <!-- 最多的一个connection空闲时间 -->
    37         <property name="maxIdleTime">30</property>
    38         <!-- 最多可以有多少个连接connection -->
    39         <property name="maxPoolSize">4</property>
    40         <!-- 最少的池中有几个连接 -->
    41         <property name="minPoolSize">2</property>
    42         <!-- 批处理的语句-->
    43         <property name="maxStatements">50</property>
    44         <!-- 每次增长几个连接 -->
    45         <property name="acquireIncrement">2</property>
    46         <property name="driverClass">com.mysql.jdbc.Driver</property>
    47         <property name="jdbcUrl">
    48             <![CDATA[jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8]]>
    49         </property>
    50         <property name="user">root</property>
    51         <property name="password">5a6f38</property>
    52     </named-config> 
    53 </c3p0-config>
    c3p0-config.xml

      1.首先定义一个接口ResultSetHandler,该接口是BeanListHandler等类的父接口,借口中定义了唯一一个方法handler();(调用规范)

    public interface ResultSetHandler<T> {
        public T handler(ResultSet rs);
    }

      2.自定义QueryRunner类(调用类)

    package day17.kdyzm.CallBack;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    import javax.sql.DataSource;
    
    public class QueryRunner {
        private DataSource ds;
        public QueryRunner(DataSource ds){
            this.ds=ds;
        }
        public <T> T query(String sql,ResultSetHandler<T> rsh)
        {
            T  t=null;
            Connection conn=null;
            try {
                conn=ds.getConnection();
                Statement st=conn.createStatement();
                ResultSet rs=st.executeQuery(sql);
                t=rsh.handler(rs);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            finally{
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return t;
        }
    }

      3.定义javabean

    package day17.kdyzm.CallBack;
    
    public class Person {
        private String id;
        private String name;
        private int age;
        private String sex;
        public Person() {
        }
        public Person(String id, String name, int age, String sex) {
            super();
            this.id = id;
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            //这里一旦改成int,则反射的时候就找不到方法了,该怎么修改才能解决这个问题?使用返回值类型得到set方法中的参数类型
            this.age = age;
        }
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
        @Override
        public String toString() {
            return "Person [id=" + id + ", name=" + name + ", age=" + age
                    + ", sex=" + sex + "]";
        }
    }

      4.定义一个具体类用于实现ResultSetHandler接口。这里使用BeanListHandler,返回值一定是List,但是泛型参数类型不确定,直到给出确切的泛型类型。

    package day17.kdyzm.CallBack;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * 实现了ResultSetHandler接口的实现类。
     * @author kdyzm
     *
     */
    public class BeanListHandler<T> implements ResultSetHandler<List<T>>{
        private Class<T> clazz;
        public BeanListHandler(Class<T>clazz){
            this.clazz=clazz;
        }
        @Override
        public List<T> handler(ResultSet rs) {
            List<T>list=new ArrayList<T>();
            try {
                ResultSetMetaData rsdm=rs.getMetaData();
                int columnNum=rsdm.getColumnCount();
                while(rs.next())
                {
                    T t=clazz.newInstance();
                    for(int i=0;i<columnNum;i++)
                    {
                        String columnName=rsdm.getColumnName(i+1);
                        String methodName="set"+columnName.substring(0,1).toUpperCase()+
                                columnName.substring(1).toLowerCase();
                        String methodName_p="get"+columnName.substring(0,1).toUpperCase()+
                                columnName.substring(1).toLowerCase();
    //                    String classType=rsdm.getColumnClassName(i+1);//通过这种方式获得的返回类型有问题。
                        Method method_p=clazz.getMethod(methodName_p);
                        Method method=clazz.getMethod(methodName, method_p.getReturnType());
                        Object obj=rs.getObject(columnName);
                        method.invoke(t, obj);
                    }
                    list.add(t);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return list;
        }
        
    }

      5.测试

    package day17.kdyzm.CallBack;
    
    import java.util.List;
    
    import javax.sql.DataSource;
    
    import day17.regular.utils.DataSourceUtils_C3P0;
    
    /**
     * 测试回调函数的测试类
     * @author kdyzm
     *
     */
    public class Test {
        public static void main(String[] args) {
            DataSource ds=DataSourceUtils_C3P0.getDataSource();
            QueryRunner run=new QueryRunner(ds);
            String sql="select * from people";
            List<Person>list=run.query(sql, new BeanListHandler<Person>(Person.class));
            for(Person p:list)
            {
                System.out.println(p);
            }
            System.out.println("回调函数开发成功!");
        }
    }

      6.运行结果

    c3p0数据库初始化日志信息略;
    Person [id=001, name=张三, age=12, sex=男]
    Person [id=002, name=李四, age=13, sex=男]
    Person [id=003, name=王五, age=15, sex=男]
    回调函数开发成功!
  • 相关阅读:
    NOIP 模拟 序列操作
    LUOGU 1525 关押罪犯
    HDU2473 Junk-Mail Filter
    BZOJ 2096 Pilots
    luogu 3939 数颜色
    NOIP模拟 赌博游戏
    Unity3D
    HTML5
    Cocos2d-x——支持多触点
    Cocos2d-x——Cocos2d-x 屏幕适配总结
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4690128.html
Copyright © 2020-2023  润新知