【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=男]
回调函数开发成功!
时间: 2024-10-30 08:33:12

【Java EE 学习第17天】【dbutils和回调函数】的相关文章

【Java EE 学习第17天】【数据库导出到Excel】【多条件查询方法】

一.导出到Excel 1.使用DatabaseMetaData分析数据库的数据结构和相关信息. (1)测试得到所有数据库名: private static DataSource ds=DataSourceUtils_C3P0.getDataSource(); Connection conn=ds.getConnection(); DatabaseMetaData dbmd=conn.getMetaData(); ResultSet rs=dbmd.getCatalogs(); while(rs.

【Java EE 学习第16天】【dbcp数据库连接池】【c3p0数据库连接池】

零.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: 1 package day16.utils; 2 3 import java.io.IOException; 4 import java.lang.reflect.InvocationHandler; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Proxy; 7 import java.sql.Connection; 8 import java.sql.D

Java EE学习——Quartz的Cron表达式

经历过低谷后,还是要好好学习,越失落会越来越落后. 今天写一下Cron表达式的用法,虽然是之前自己写的,也过了挺长一段时间,这次就拿出来作为回顾吧. Cron表达式是Quartz的精髓(个人觉得),比如我们想设定淘宝“秒杀”的那一秒时间,完全可以用下面的方法设置执行时间. Calendar cal = Calendar.getInstance(); //设置将要发生的时间... cal.set(Calendar.DATE, xxx); //.......常规的生成scheduler和job //

Java EE学习之旅2——Ant

上次也了解了一下Ant是啥了,就是管理Java生成的工具嘛. 然后今天来学习一下如何使用Ant. 首先是指令: -find和-s Ant会一直到上级目录搜索build.xml,直到到达文件系统根目录: -buildfile.-file和-f 使用其他生成文件,例如a.xml: -quiet和-q 运行时只输出少数提示信息: -verbose和-v 输出多一点的提示信息. 2014-07-12 22:17:14 Java EE学习之旅2--Ant

Java EE学习--Quartz基本用法

新浪博客完全不适合写技术类文章.本来是想找一个技术性的博客发发自己最近学的东西,发现博客园起源于咱江苏,一个非常质朴的网站,行,咱要养成好习惯,以后没事多总结总结经验吧.很多时候都在网上搜索别人的总结,我自己也总结些东西,或许多多少少能帮得上别人. 首先提到的是Quartz,一个开源的定期执行计划任务的框架.其实我内心好奇这个框架很久了,像那些能定时修改数据库数据,定时分配任务的功能一直觉得很神奇.心动不如行动,今天我就小小的学习了一下用法,力求言简意赅,大家都懂的我就不说了. 第一步:下载Qu

Java EE 学习(7):IDEA + maven + spring 搭建 web(3)- 配置数据库

参考: https://my.oschina.net/gaussik/blog/513444 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) Java EE 学习(6):IDEA + maven + spring 搭建 web(2) 5 数据库配置 下面,就要通过一个简单的例子,来介绍 SpringMVC 如何集成 Spring Data JPA(由 Hibernate JPA 提供),来进行强大的数据库访问,并通过本章节

JAVA EE 学习笔记[V1 jsp编程]

在三月初学校开设了javaee的课程,也就此展开了对javaee基础的学习.然后老师也对这次的课程有一定要求.前面的基础就为最终的作业做准备啦~ 在上学期我们学习了java相关知识,也对java se 的安装使用有了一定的认知,而java ee则是构建于java se 平台之上的一套多层的,可扩展的的网络应用. 学习java ee我们首先进行环境的搭建.无非就是使用 tomcat进行服务器的搭建和jdk环境变量配置.而IDE这方面我们选择myeclipse 2016 CI(这个编译器自带tomc

Java EE 学习(5):IDEA + maven + spring 搭建 web(1)

参考:http://www.cnblogs.com/lonelyxmas/p/5397422.html http://www.ctolib.com/docs-IntelliJ-IDEA-c--159047.html 孔老师的<SpringMVC视频教程> 记录: 本节主要完成 使用 maven 管理 spring + 项目 包,搭建 maven+spring 的 web 项目平台. 前提: 已安装并配置好 - Intellij IDEA 16.3.5 Ultimate - JDK 1.8.0_

Java EE 学习(8):IDEA + maven + spring 搭建 web(4)- 用户管理

转载:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) ava EE 学习(6):IDEA + maven + spring 搭建 web(2)- 配置 Spring Java EE 学习(7):IDEA + maven + spring 搭建 web(3)- 配置数据库 记录: 通过对用户表的管理,更加深入地讲解SpringMVC的操作. 6 用户管理 既然我们