使用回调函数,简单模拟dbutils中Queryrunner的工作原理,并重写Queryrunner,使其使用起来更加简单方便

所谓回调,就是在执行某个程序时,具体的封装处理由第三方类来实现,简单一点说就是记录内部,再出来(由第三方类可以对数据进行处理),再返回去继续执行,这个过程就是回调。想要程序具有记录内部的功能就必须定义一个规范,也就是接口,即你的程序出来被其他类处理了,但你规定了还要返回原程序。

下面看一个简单的例子:

/**
 * @描述:回调函数--记录内部,再出来返回去的过程就叫回调
 * @author cxie
 */
public class CopyOfCallBackDemo {
	public static void main(String[] args) {
		QRunner run = new QRunner();
		run.query("cxie",new RunnerHandler1(){
			@Override
			public void handler(String name) {
				System.err.println(name+"1");
			}
		});
	}
}
/**
 * 定义调用类
 */
class QRunner{
	public void query(String sql,RunnerHandler1 rh){
		//调用规范的实现类
		System.err.println(sql+"o");
		rh.handler(sql);
	}
}
/**
 * 定义回调规范
 */
interface RunnerHandler1{
	void handler(String name);
}

程序的执行结果如下

下面再看一个高级一点的例子,通过定义泛型,使回调具有任意的返回值

<span style="font-size:18px;">package hd.cx.dbutilTest;

import java.util.List;
import java.util.Map;

/**
 * @描述:回调函数--记录内部,再出来返回去的过程就叫回调
 * @author 刘楚燮
 * @拓展:通过定义泛型,使回调具有任意的返回值
 *
 */
public class CallBackDemo {

	public static void main(String[] args) {
		Runner run = new Runner();
		run.query("zhangsan",new RunnerHandler<List<Map<String, Object>>>()/** 定义了该方法的规范*/{
			@Override
			public List<Map<String,Object>> handler(String name){
				System.err.print(name+"1");
				return null;

			}
		});

	}
}

/**
 * 定义一个调用类
 */
class Runner{
	public <T>/**这里是定义泛型*/ T  query(String sql,RunnerHandler<T>/**这里是使用泛型*/ rh){
		//调用一规范的实现类
		System.err.println(sql+"0");
		return rh.handler(sql);
	}
}
/**
 * 定义一个回调规范:接口
 */

interface RunnerHandler<T>{
	T handler(String name);
}</span>

程序的运行结果同样如下

由此可以看出程序先执行调用类再回调回去执行接口定义的方法。

接下来是简单模拟Queryrunner中的两种方法来来编写自己的Queryrunner(一种是封装成Map放到List中,一种是封装到JavaBean中,暂时先不使用回调函数,大概了解一下原理)

<span style="font-size:18px;">import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import java.sql.Statement;

/**
 * @描述:模拟queryrunner编写一个封装数据库操作的方法
 * @author cxie
 *
 */
public class QueryRunner {
	private DataSource ds;
	public QueryRunner(){

	}
	public QueryRunner(DataSource ds){
		this.ds=ds;
	}
	/**
	 * 只封装List<Map>
	 */
	public List<Map<String,Object>> query(String sql){
		//封装数据用
		List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();//声明返回对象
		Connection con = null;
		try {
			con = ds.getConnection();
			//执行查询
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery(sql);
			//分析结果集
			ResultSetMetaData rsmd = rs.getMetaData();
			//获取列数
			int cols = rsmd.getColumnCount();
			System.err.println("列数:"+cols);
			//遍历数据
			while(rs.next()){
				Map<String,Object> mm = new HashMap<String, Object>();
				//遍历列
				for(int i = 0;i<cols;i++){//0,1,2,3
					//获取列名
					String colName = rsmd.getColumnName(i+1);//1,2,3,4
					//获取数据
					Object val = rs.getObject(i+1);
					//封装到Map里面
					mm.put(colName, val);
				}
				list.add(mm);
			}

		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally{
			try {
				con.close();
			} catch (SQLException e) {

				e.printStackTrace();
			}
		}

		return list;
	}

	/**
	 * 封装成List<bean>
	 * <T>定义泛型
	 * List<T>使用泛型
	 * Class<T> 接收一个T类型的字节码对象
	 * Type是class父类
	 * 记得bean中要覆盖toString方法
	 */
	public <T> List<T> queryForBean(String sql,Class<T> cls){
		//声明返回对象
		List<T> list = new ArrayList<T>();
		//获取连接
		Connection con = null;
		try{
			con = ds.getConnection();
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery(sql);
			ResultSetMetaData rsmd = rs.getMetaData();
			//获取列数
			int cols = rsmd.getColumnCount();
			while(rs.next()){
				//每次遍历一行,应该实例化一个bean
				T t = cls.newInstance();
				//遍历所有列
				for(int i = 0;i<cols;i++){
					String colName = rsmd.getColumnName(i+1);//获取列名
					colName = colName.toLowerCase();//全部转为小写
					//将colName转成setXxx
					String methodName = "set"+colName.substring(0,1).toUpperCase()+colName.substring(1).toLowerCase();
					//通过数据库获取数据库对应的java类型QName
					//varchar - java.lang.String , int -- java.lang.Integer
					String javaType = rsmd.getColumnClassName(i+1);
					//反射出T的方法
					try{
						Method method = cls.getMethod(methodName, Class.forName(javaType));
						//执行,查询数据库
						Object value = rs.getObject(colName);
						method.invoke(t, value);//调用JavaBean的set方法把值set进去
					}catch(Exception e){
						//e.printStackTrace();
					}

				}
				list.add(t);
			}

		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				con.close();
			} catch (SQLException e) {

				e.printStackTrace();
			}
		}

		return list;
	}
}</span>

本次使用的数据库连接方法仍然是c3p0连接池,具体实现方法请看我上篇博客:通过使用反射+动态代理+注解来实现对事务的控制

接下来编写一个测试方法:

<span style="font-size:18px;">package hd.cx.demo;

import java.util.List;
import java.util.Map;

import org.junit.Test;

import hd.cx.utils.DataSourceUtils;
import hd.cx.queryrunner.QueryRunner;

public class DaoTest {
	@Test
	public void test1(){
		QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());
		String sql = "select * from user";
		List<Map<String, Object>> list = run.query(sql);
		System.out.println(list);
	}
}</span>

运行结果如下

封装成List<bean>的测试类如下:

<span style="font-size:18px;">@Test
	public void test2(){
		QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());
		String sql = "select * from user";
		List<User> list = run.queryForBean(sql,User.class);
		System.out.println(list);
	}</span>

运行结果

接下来是模拟dbutils中的方法,使用回调函数编写一个自己的BeanListHandler,方法大致跟上面的一样,具体代码如下

回调函数:

<span style="font-size:18px;">	/**
	 * 有回调的查询
	 */

	public <T> T query(String sql,MyHandler<T> mh){
		T t = null;
		//声明conn
		Connection con = null;
		try {
			con = ds.getConnection();
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery(sql);
			//让回调去执行数据库封装
			t = mh.handler(rs);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				con.close();
			} catch (SQLException e) {

				e.printStackTrace();
			}
		}
		return t;
	}
	</span>

被调用的第三方类:

具体实现都差不多就不写注释了

<span style="font-size:18px;">package hd.cx.queryrunner;

import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

public class MyBeanListHandler<T> implements MyHandler<List<T>> {
	private Class<T> cls;
	/**传入bean的字节码*/
	public MyBeanListHandler(Class<T> cls){
		this.cls=cls;
	}
	@Override
	public List<T> handler(ResultSet rs) {
		List<T> list = new ArrayList<T>();
		try {
			ResultSetMetaData rsmd = rs.getMetaData();
			int cols = rsmd.getColumnCount();
			while(rs.next()){
				T t = cls.newInstance();
				for(int i = 0; i<cols;i++){
					String colsName = rsmd.getColumnName(i+1);
					String methodName =
							"set" + colsName.substring(0,1)
							.toUpperCase()
							+colsName.substring(1).toLowerCase();
					String javaType = rsmd.getColumnClassName(i+1);
					try {
						Method mm = cls.getMethod(methodName, Class.forName(javaType));
						Object val = rs.getObject(i+1);
						mm.invoke(t, val);
					} catch (Exception e) {
						//异常不要处理
					}

				}
				list.add(t);
			}
		} catch (Exception e) {

		}
		return list;
	}

}</span>

定义的规范,也就是接口:

<span style="font-size:18px;">package hd.cx.queryrunner;
/**
 * @描述:定义规范,接受rs结果集
 * @author cxie
 */
import java.sql.ResultSet;

public interface MyHandler<T> {
	T handler(ResultSet rs);
}</span>

接下来编写一个测试方法

<span style="font-size:18px;">	@Test
	public void test3(){
		QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());
		String sql = "select * from user";
		List<User> list = run.query(sql, new MyBeanListHandler<User>(User.class));
		System.out.println(list);
	}</span>

运行结果如下:

再来看一下dbutils中beanlisthandler的执行方法

<span style="font-size:18px;">@Test
	public void test4(){
		org.apache.commons.dbutils.QueryRunner run = new org.apache.commons.dbutils.QueryRunner(DataSourceUtils.getDatasSource());
		String sql = "select * from user";
		List<User> list = null;

			try {
				list = run.query(sql, new BeanListHandler<User>(User.class));
			} catch (SQLException e) {

				e.printStackTrace();
			}

		System.out.println(list);
	}</span>

执行结果都是一样的,这里就不列出来了。

如果仔细一点的话就能发现,当调用dbutils中的方法时需要捕获异常,而调用MyBeanListHandler时确实不用,原因在于编写MyBeanListHandler时已经对异常进行了捕获,所以我们可以重写dbutils中的Queryrunner呢,捕获每个方法的异常,这样每次调用的时候就不必要try-catch了。其实说白了很简单,就是继承dbutils的Queryrunner,对父类的方法进行try-catch覆盖,

下面是dbutils的源码和jar包的下载地址

http://pan.baidu.com/s/1kT2y9FL

下面是覆盖了Queryrunner方法的完整代码如下

<span style="font-size:18px;">package hd.cx.utils;

import java.beans.PropertyDescriptor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;

/**
 * @描述:重写Queryrunner,避免try-catch的麻烦
 * @author cxie
 *
 */
public class MyQueryRunner extends QueryRunner{
	public MyQueryRunner(){}
	public MyQueryRunner(DataSource ds){
		super(ds);
	}
	@Override
	public int[] batch(Connection conn, String sql, Object[][] params) {
		try {
			return super.batch(conn, sql, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	}

	@Override
	 public int[] batch(String sql, Object[][] params){
		try {
			return super.batch(sql, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	}
	@Override
	 public void fillStatement(PreparedStatement stmt, Object... params){
		 try {
			super.fillStatement(stmt, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 public void fillStatementWithBean(PreparedStatement stmt, Object bean,
	            PropertyDescriptor[] properties){
		 try {
			super.fillStatementWithBean(stmt, bean, properties);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 public void fillStatementWithBean(PreparedStatement stmt, Object bean,
	            String... propertyNames){
		 try {
			super.fillStatementWithBean(stmt, bean, propertyNames);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 protected PreparedStatement prepareStatement(Connection conn, String sql){
		 try {
			return super.prepareStatement(conn, sql);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}

	 }
	@Override
	 protected Connection prepareConnection(){
		 try {
			return super.prepareConnection();
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 public <T> T query(Connection conn, String sql, Object param,
	            ResultSetHandler<T> rsh){
		 try {
			return super.query(conn, sql, rsh);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public <T> T query(Connection conn, String sql, Object[] params,
	            ResultSetHandler<T> rsh){
		 try {
			return super.query(conn, sql, params, rsh);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}

	 }
	@Override
	 public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh,
	            Object... params){
		 try {
			return super.query(conn, sql, rsh, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh){
		 try {
			return super.query(conn, sql, rsh);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 public <T> T query(String sql, Object param, ResultSetHandler<T> rsh){
		 try {
			return super.query(sql, param, rsh);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh){
		 try {
			return super.query(sql, params, rsh);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params){
		 try {
			return super.query(sql, rsh, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 public <T> T query(String sql, ResultSetHandler<T> rsh){
		 try {
			return super.query(sql, rsh);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }
	@Override
	 protected void rethrow(SQLException cause, String sql, Object... params){
		 try {
			super.rethrow(cause, sql, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public int update(Connection conn, String sql){
		 try {
			 return super.update(conn, sql);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public int update(Connection conn, String sql, Object param){
		 try {
			return super.update(conn, sql, param);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public int update(Connection conn, String sql, Object... params){
		 try {
			return super.update(conn, sql, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public int update(String sql){
		 try {
			return super.update(sql);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public int update(String sql, Object param){
		 try {
			return super.update(sql, param);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 public int update(String sql, Object... params){
		 try {
			return super.update(sql, params);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 protected void close(Connection conn){
		 try {
			super.close(conn);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 protected void close(Statement stmt){
		 try {
			super.close(stmt);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

	@Override
	 protected void close(ResultSet rs){
		 try {
			super.close(rs);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(),e);
		}
	 }

}
</span>

如此这般,就可以省去try-catch的麻烦了,由于篇幅的问题,这里就不写测试类了。

时间: 2024-10-11 22:28:40

使用回调函数,简单模拟dbutils中Queryrunner的工作原理,并重写Queryrunner,使其使用起来更加简单方便的相关文章

JavaScript中this的工作原理以及注意事项

在JavaScript中,this 的概念比较复杂.除了在面向对象编程中,this 还是随处可用的.这篇文章介绍了this 的工作原理,它会造成什么样的问题以及this 的相关例子. 要根据this 所在的位置来理解它,情况大概可以分为3种: 1.在函数中:this 通常是一个隐含的参数. 2.在函数外(顶级作用域中):在浏览器中this 指的是全局对象:在Node.js中指的是模块(module)的导出(exports). 3.传递到eval()中的字符串:如果eval()是被直接调用的,th

利用反射模拟一个spring的内部工作原理

这个简单的案例是实行了登录和注册的功能,没有链接数据库. 在bean中id 是唯一的,id和name的区别在于id不能用特殊字符而name可以用特殊字符,比如:/-\.... 1 package com.obtk.reflect; 2 3 public class Logon { 4 /** 5 * 帐号密码长度大于六位字符就成功,否则失败! 6 * */ 7 public String select(String name, String pass) { 8 if (name.length()

回调函数在replace方法中的应用

处理字符串是项目中经常会遇到的问题,对于长度比较大的字符串如何作一次性处理是需要我们去考虑的,这里给个例子: 把字符串"get-element-by-id"变成"getElementById": 方法一: var a = "get-by-element-by-id"; var b = a.split("-") for(var i = 1 ;i<b.length;i++){ b[i].charAt(0).toUpperCa

Java简单模拟Android中Handler-Message机制

在Android中主线程与子线程的通信十分重要,Google工程师为我们提供了Handler-Message机制来解决他们之间的交互问题.今天,我们就来简单理解Handler-Message机制的原理,在Java中简单模拟该机制.代码示例Github地址HandlerDemo 首先,看一下简单流程图(不太专业) 由上图可知,流程中主要相关类有Handler.Message.MessageQueue.Looper:下面,我们就围绕它们来简单分析该流程图: 1.我们一般在主线程创建Handler,接

PCL中将回调函数封装到类中

这是类中的声明 private://点云回调函数 NuClearTask_MyPointCloudHandle //点云选择 static void ps_callback(const pcl::visualization::AreaPickingEvent& event, void* object) { NuClearTask *pThisObject = (NuClearTask*)object; pThisObject->PointSelect_callback(event); } v

解析Vue.js中的computed工作原理

我们通过实现一个简单版的和Vue中computed具有相同功能的函数来了解computed是如何工作的.写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. JS属性: JavaScript有一个特性是 Object.defineProperty ,它能做很多事,但我在这篇文章只专注于这个方法中的一个: var person = {}; Object.defineProperty (person, 'age', { get: function ()

Tomcat中JSP引擎工作原理

http://blog.csdn.net/linjiaxingqqqq/article/details/7164449 JSP运行环境: 执行JSP代码需要在服务器上安装JSP引擎,比较常见的引擎有WebLogic和Tomcat.把这些支持JSP的web服务器配置好后.就可以再客户端通过浏览器来访问JSP页面了.默认端口一般是7001. JSP生命周期: JSP处理请求的方法就是把这些请求都统一看做Servlet.由于这个原因,JSP的很多功能和生命周期,都由Java Servlet技术标准定义

Java中GC的工作原理

转文: 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能提高整个应用程序的性能.本文将从GC的工作原理.GC的几个关键问题进行探讨,最后提出一些Java程序设计建议,如何从GC角度提高Java程序的性能. 一.GC的基本原理: GC是什么? 为什么要有GC呢? GC是垃圾收集的意思(Garbage Collection),内存处理是编程人员容易出现问题的地方,忘

多线程之:模拟实现线程池的工作原理

[一]线程池存在的价值: ==>多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.    ==>假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间. ==>如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能. [二]合理利用线程池能够带来三个好处. * 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. * 第二:提高响应速度.