利用反射和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 试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有 ...
随机推荐
- SQL基础巩固1
直接开门见山------F4 1.查询 对指定的数据表或是视图进行检索查询,找出符合查询条件功能,具体包括以下SQL语法如下所示,其中[]为可选项 Select<列名> From<表 ...
- ionic下拉加载自动触发
ionic提供的下拉加载,是要滑动去下拉加载,没有提供api自动触发下拉加载,比如刚进页面,或者切换tab时想触发一次下拉加载. 添加如下service: angular.module('YourAp ...
- awk实现按照某个字段排序
awk 'BEGIN{ FS="|"} { ary[$14,NR]=$0} END{ nrw=asorti(ary, newary) for(i=1;i<=nrw;i++) ...
- linux环境下配置java WEB项目运行环境,jdk8+tomcat8+mysql5.7.11 新手向
一:安装jdk 1.下载jdk 在oracle下载东西的时候因为oracle的一些验证机制,所以需要在链接前面添加一些参数 wget --no-check-certificate --no-cook ...
- 游戏制作之路:一个对我来说可实现的High-end的Mac/iOS游戏制作大概计划
对于学习一些东西,我比较习惯任务驱动式的学习,也就是说,要事先订好一个目标,要做什么东西,达到什么效果,然后根据自己了解的知识作一个可以实现这个目标的计划. 现在要学的是游戏制作,而且是High-en ...
- HttpClient_001_初步实现项目01的servlet,与项目02的servlet,之间数据访问
HttpClient_001_初步实现项目01的servlet,与项目02的servlet,之间数据访问 代码下载地址: http://download.csdn.net/detail/poiuy19 ...
- Java语言的特点
一. 面向对象:其实是现实世界模型的自然延伸.现实世界中任何实体都可以看作是对象.对象之间通过消息相互作用.另外,现实世界中任何实体都可归属于某类事物,任何对象都是某一类事物的实例.如果说传统的过程式 ...
- php学习01
- mina IoBuffer 常用方法
Limit(int) 如果position>limit, position = limit,如果mark>limit, 重置mark Mark() 取当前的position的快照标记mar ...
- [已解决] java.net.InetAddress.getHostName() 阻塞问题
在学习java nio的过程中发现某些情况下使用该方法会导致程序阻塞,(情况:服务器,Linux:客户端,WIN10) java.net.InetAddress.getHostName() 阻塞情况如 ...