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

来源:互联网 发布:淘宝装修公司靠谱吗 编辑:程序博客网 时间:2024/05/19 03:45

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

下面看一个简单的例子:

/** * @描述:回调函数--记录内部,再出来返回去的过程就叫回调 * @author cxie */public class CopyOfCallBackDemo {public static void main(String[] args) {QRunner run = new QRunner();run.query("张三",new RunnerHandler1(){@Overridepublic 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 cxie * @拓展:通过定义泛型,使回调具有任意的返回值 * */public class CallBackDemo {public static void main(String[] args) {Runner run = new Runner();run.query("zhangsan",new RunnerHandler<List<Map<String, Object>>>()/** 定义了该方法的规范*/{@Overridepublic 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()){//每次遍历一行,应该实例化一个beanT t = cls.newInstance();//遍历所有列for(int i = 0;i<cols;i++){String colName = rsmd.getColumnName(i+1);//获取列名colName = colName.toLowerCase();//全部转为小写//将colName转成setXxxString methodName = "set"+colName.substring(0,1).toUpperCase()+colName.substring(1).toLowerCase();//通过数据库获取数据库对应的java类型QName//varchar - java.lang.String , int -- java.lang.IntegerString 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 {@Testpublic 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;">@Testpublic 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;//声明connConnection 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;}@Overridepublic 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;">@Testpublic 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;">@Testpublic 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);}@Overridepublic 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的麻烦了,由于篇幅的问题,这里就不写测试类了。



0 0
原创粉丝点击