【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=男]
回调函数开发成功!
原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4690128.html