利用反射和ResultSetMetaData实现DBUtils的基本功能
DBUtils大大简化了JDBC的书写,极大的提高了开发效率,和数据库连接池一起,简化了JDBC开发的流程.简易的自定义数据库连接池可以通过装饰者设计模式和动态代理模式得到很简单的实现,那么DBUtils应该怎么实现呢?为了了解DBUtils其内部工作的流程,我实现了一个自己的DBUtils工具类,实现一些简单的更新和查询操作.
ResultSetMetaData是可以获取ResultSet对象的列类型和属性信息的对象.这个类里面有很多方法,在这个案例中,只用到两个:getColumnCount():获取ResultSet结果集中列的数目.getColumnName(int column):根据指定的列数目获取列名.有了这两个方法就可以自己动手去实现一个简易版的DBUtils啦~下面是我实现的步骤:
1.编写MyQueryRunner的executeUpdate方法.
这个方法的编写非常简单,因为可以通过dataSource获取Connection,在方法的内部就是简单的jdbc操作.需要注意的是,需要手动设置传入的参数到PreparedStatement中.代码如下:
public int update(String sql, Object... params) {
Connection connection=null;
PreparedStatement preparedStatement=null;
try {
connection=dataSource.getConnection();
preparedStatement=connection.prepareStatement(sql);
for(int i=0;i<params.length;i++) {
preparedStatement.setObject((i+1), params[i]);//设置参数.
}
int x=preparedStatement.executeUpdate();//执行更新操作.
return x;
} catch (SQLException e) {
throw new RuntimeException(e);
}
finally {
if(preparedStatement!=null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.编写MyQueryRunner的executeQuery方法.
这个方法的实现也不难,因为我们将重要的代码交给传入的ResultSetHandler实现对象来处理.代码如下:
//查询会比较麻烦.
//作出三个实现BeanHandler BeanListHandler MapListHandler
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) {
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet rs=null;
try {
connection=dataSource.getConnection();
preparedStatement=connection.prepareStatement(sql);
if(params!=null) {
for(int i=0;i<params.length;i++) {
preparedStatement.setObject((i+1), params[i]);
}
}
rs=preparedStatement.executeQuery();
return rsh.handle(rs);//交给处理器处理
} catch (SQLException e) {
throw new RuntimeException(e);
}
finally {
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.3个处理器的编写.
在MyQueryRunner实现自定义查询的实现中,我实现了三个处理器,它们分别是采用了BeanHandler,BeanListHandler,MapListHandler的实现思想,并且给出了最简单易懂(实际上是因为我水平不够= =)的实现.下面说说BeanHandler的实现流程,Handler的实现基本上都是一样的,无非是采用反射获得元素对象,并且将数据封装进去.
BeanHandler中有两个成员变量,一个T t用来作为要返回的JavaBean,声明在外面供之后封装数据使用,一个Class type对象,用来获取Class,创建JavaBean对象赋值给t,创建Field对象为t的成员变量赋值.在方法的实现中,先通过getColumnCount方法来获取列的数目,遍历每一列,通过getColumnName(int columnCount)方法获取列名,用Class对象的getField方法获取Field对象(这里JavaBean的取值一定要和数据库中相同!否则会报错),再利用Field对象的set方法赋值.当然Field对象对应的成员变量一定是私有的(JavaBean的特性.)因此需要先调用setAccessable方法才可以.具体的代码如下:
public class MyBeanHandler<T> implements ResultSetHandler{
private Class<T> type;
T t;//需要封装的JavaBean
public MyBeanHandler(Class<T> type) {
this.type=type;
} @Override
public Object handle(ResultSet rs) throws SQLException {
try {
t=type.newInstance();
ResultSetMetaData metaData = rs.getMetaData();
int count=metaData.getColumnCount();//获取ResultSet中数据的列数
rs.next();//移动指针
//遍历获的每一列的列名,采用反射机制设置值
for(int i=1;i<=count;i++) {
String name=metaData.getColumnName(i);
Object obj=rs.getObject(i);
Field field = type.getDeclaredField(name);
field.setAccessible(true);
field.set(t, obj);//封装数据进入JavaBean
}
} catch (Exception e) {
e.printStackTrace();
}
return t;
} }
MyBeanListHandler的实现步骤,基本和BeanHandler一致.唯一的区别就是采用结果集的next方法遍历每一条记录,而将对象的创建移动到了循环里,这里考虑返回的List对象的增删应该比较少因此采用的是ArrayList.具体实现如下:
public class MyBeanListHandler<T> implements ResultSetHandler<List<T>>{
private Class<T> type;
List<T> list=new ArrayList<T>();//可能获取比较多.因此采用ArrayList public MyBeanListHandler(Class<T> type) {
this.type = type;
} @Override
public List<T> handle(ResultSet rs) throws SQLException {
try {
ResultSetMetaData metaData = rs.getMetaData();
int count=metaData.getColumnCount();
while(rs.next()) {
T t=type.newInstance();
for(int i=1;i<=count;i++) {
String name=metaData.getColumnName(i);//该方法获取列名.获取一系列字段名称.例如name,age...
Object obj=rs.getObject(i);//获取字段值
Field field = type.getDeclaredField(name);//获取field对象
field.setAccessible(true);
field.set(t, obj);//设置值
}
list.add(t);
}
return list;
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
MapList看上去似乎最复杂,但是实际上实现起来却由于没有采用泛型和反射,是最方便的,代码如下:
public class MyMapListHandler implements ResultSetHandler<List<Map<String, Object>>> { private List<Map<String,Object>> data=new ArrayList<>(); @Override
public List<Map<String, Object>> handle(ResultSet rs) throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
int count=metaData.getColumnCount();
while(rs.next()) {
Map<String,Object> map=new HashMap<>();
for(int i=1;i<=count;i++) {
Object value=rs.getObject(i);
String name=metaData.getColumnName(i);
map.put(name, value);
}
data.add(map);
}
return data;
} }
利用反射和ResultSetMetaData实现DBUtils的基本功能的更多相关文章
- <五>JDBC_利用反射及JDBC元数据编写通用的查询方法
此类针对javaBean类写了一个通用的查询方法,List<javaBean> 通用查询更新中...:通过学习,深刻体会到学会反射就等于掌握了java基础的半壁江山! 一.使用JDBC驱动 ...
- 利用反射及JDBC元数据编写通用查询方法
元数据:描述数据的数据,ResultSetMetaData是描述ResultSet的元数据对象,从它可以得到数据集有多少了,每一列的列名... ResultSetMetaData可以通过ResultS ...
- 利用反射及jdbc元数据实现通用的查询方法
---------------------------------------------------------------------------------------------------- ...
- JDBC学习笔记(5)——利用反射及JDBC元数据编写通用的查询方法
JDBC元数据 1)DatabaseMetaData /** * 了解即可:DatabaseMetaData是描述数据库的元数据对象 * 可以由Connection得到 */ 具体的应用代码: @Te ...
- 【转】JDBC学习笔记(5)——利用反射及JDBC元数据编写通用的查询方法
转自:http://www.cnblogs.com/ysw-go/ JDBC元数据 1)DatabaseMetaData /** * 了解即可:DatabaseMetaData是描述数据库的元数据对象 ...
- Java -- JDBC_利用反射及 JDBC 元数据编写通用的查询方法
先利用 SQL 进行查询,得到结果集: 利用反射创建实体类的对象:创建对象: 获取结果集的列的别名: 再获取结果集的每一列的值, 结合 3 得到一个 Map,键:列的别名,值:列的值: 再利用反射为 ...
- Java JDBC利用反射技术将查询结果封装为对象
1.JDBC将返回结果集封装成对象demo class JdbcDemo { /** * 获取数据库列名 * @param rs * @return */ private static String[ ...
- MYSQL 之 JDBC(六): 增删改查(四)利用反射及JDBC元数据编写通用的查询
1.先利用SQL进行查询,得到结果集2.利用反射创建实体类的对象:创建Student对象3.获取结果集的列的别名:idCard.studentName4.再获取结果集的每一列的值,结合3得到一个Map ...
- 【转】利用反射快速给Model实体赋值
原文地址:http://blog.csdn.net/gxiangzi/article/details/8629064 试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有 ...
随机推荐
- dubbo 试用全过程
概述: dubbo服务容器是一个standalone的启动程序,因为后台服务不需要Tomcat或JBoss等Web容器的功能,如果硬要用Web容器去加载服务提供方,增加复杂性,也浪费资源. 服务容器只 ...
- iOS仿网易新闻栏目拖动重排添加删除效果
仿网易新闻栏目选择页面的基本效果,今天抽了点时间教大家如何实现UICollectionView拖动的效果! 其实实现起来并不复杂,这里只是基本的功能,没有实现细节上的修改,连UI都是丑丑的样子,随手画 ...
- android如何获取到启动类的包和类路径
ArrayList<String> list = new ArrayList<String>(); private List<ResolveInfo> mApps; ...
- 什么是core dump linux下用core和gdb查询出现"段错误"的地方
什么是core dump linux下用core和gdb查询出现"段错误"的地方 http://blog.chinaunix.net/uid-26833883-id-31932 ...
- VMware workstaion上传虚拟机到VMware EXSI 5.5
1.首先在VMware Workstation 文件 --- 连接VMware EXSI5.5服务器. 2.输入VMware EXSI 5.5服务器地址.用户名和密码. 3.右键Windows 7 ...
- LuaXMLRPC笔记
XMLRPC XMLRPC 为以http为传输协议,使用xml格式化数据来执行远程过程调用, 区别于本地过程调用, 即发生在不同主机之间. 属于分布式计算的一种简单实现,比web service简单易 ...
- LUA 函数式编程demo
什么是函数式编程 http://www.zhihu.com/topic/19585411/hot 函数式编程的本质函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指 ...
- lua 模块功能
lua5.1 模块理解 http://www.lua.org/manual/5.1/manual.html#pdf-module 模块 5.3 – Modules The package librar ...
- [Android Tips] 6. Parallax ViewPager
文章 http://ryanhoo.github.io/blog/2014/07/16/step-by-step-implement-parallax-animation-for-splash-scr ...
- DNS协议
DNS Message: Header 消息头部 Question DNS请求 Answer 回答请求的资源记录(Resource Record(s)) Authority 指向域的资 ...