利用反射和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 试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有 ...
随机推荐
- 混合App 框架选型
个人一直想做个App,但是学习 IOS 的过程发现 原生的做界面还是听麻烦的就放弃了.后来就转到混合式App阵营了 混合式App 定义 Hybrid App(混合模式移动应用)是指介于web-app. ...
- Day12~13(2016/2/1~2/2)
进度:实现了自定义标题栏控件并调用
- 正则基础之——捕获组(capture group)
1 概述 1.1 什么是捕获组 捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用.当然,这种引用既可以是在正则表达式内部,也可以是 ...
- linux入命令基础
查看系统版本: cat /proc/version lsb_release -a uname -a 查看进程: ps ps aux |grep #查询字符串 杀掉进程: kill #标号 强制杀掉: ...
- 【五子棋AI循序渐进】——整合完成
经过一年多的学习和探索,终于在今天得到了一些回报,在实现PVS多线程和加入了一个新的启发模式之后,搜索速度达到了120K左右,现在整合了VCF/VCT引擎.PVS混合引擎之后,棋力与连珠fiver6基 ...
- form submit时将__VIEWSTATE和__VIEWSTATEGENERATOR一起post到另外的页面,出现验证视图状态 MAC 失败。
错误信息: 验证视图状态 MAC 失败.如果此应用程序由网络场或群集承载,请确保 配置指定了相同的 validationKey 和验证算法.不能在群集中使用 AutoGenerate. 原因分析: F ...
- Oracle 触发器的简单命令
-- 创建触发器的基本命令 create or replace trigger td after delete on ss begin dbms_output.put_line('删除成功'); en ...
- Sql用变量拼语句
CREATE PROC Test_GetCollegeInfo @type int AS BEGIN ),@v int,@sql nvarchar(max) Begin )) END ELSE BEG ...
- Git 一些关于 Git、Github 的学习资源
一些关于 Git.Github 的学习资源 昨天浏览 Github 的是时候发现了 Githug 这个游戏,这个游戏用来帮助菜鸟们学习使用 Git 的. Githug is designed to g ...
- 从出租车司机到大BOSS的转型之路
来深圳之前,曾有人这样告诉我:在深圳千万不能以貌取人,打扮不起眼,也许他转身开的座驾就是宝马.奔驰;不管一个人多么邋遢俗气,也别瞧不起人家,也许他的手提袋里就是成捆的人民币现金;不管一个人打扮的多么土 ...