【JDBC系列】JDBC原生处理ResultSet

背景

最近在学习Mybatis,Mybatis在处理JDBC返回值与Java业务对象之间的转换非常方便,定义XML,标明互相之间的转换关系,即可轻松完成转换。
Mybatis是JDBC的封装,我们先来看看如果用原生的JDBC,如何完成ResultSet和Java业务对象之间的转换,会遇到哪些不便。

示例代码

Java业务PO

CityPO,包含三个字段 id,cityId,cityName。我们会写使用原生的JDBC来获取返回值。

Integer id;

Long cityId;

String cityName;

获取返回值

Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/demo", "root", "123456");

PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM SU_City limit 10");
preparedStatement.execute();

ResultSet resultSet = preparedStatement.getResultSet();  //从数据库获取的数据
ResultSetMetaData meta = resultSet.getMetaData();        //从数据库返回的数据的元数据,包含列的基本信息
int cols = meta.getColumnCount();        

List<CityPO> cityPOS = new ArrayList<CityPO>();

对象转换

我们要完成的工作就是将ResultSet转换为cityPOS。

方案一

一个比较笨的方法,就是依次判断每个列的名字,因为开发者知道数据库的哪一列对应的是业务PO中的哪个属性,如果列名和属性名相等,那么调用对应属性的set方法,如下面的代码所示。

while (resultSet.next()) {
    CityPO cityPO = new CityPO();
    for (int i = 1; i <= cols; i++) {
        if (meta.getColumnName(i).equals("id")) {
            cityPO.setId((Integer) resultSet.getObject(i));
        } else if (meta.getColumnName(i).equals("city_id")) {
            cityPO.setCity_id(Long.valueOf((Integer)resultSet.getObject(i)));
        } else if (meta.getColumnName(i).equals("city_name")) {
            cityPO.setCity_name((String) resultSet.getObject(i));
        }
        cityPOS.add(cityPO);
    }
}
缺点
  1. 转换完全和具体的业务类绑定在了一起,你如果新处理一个业务类,你得再重新写一套差不多的代码,而且随着类的属性字段的增多,你的if/else代码会越来越多,听起来是不是很恐怖。
  2. 在调用set方法时,我们需要处理类型转换,又是一长串的代码。我们这个方案没用反射,不知道set属性的类型,只能靠人为判断,很有可能出现异常。

我在cityPO.setCity_id(Long.valueOf((Integer)resultSet.getObject(i))) 就遇到了把Integer直接强转Long失败,报出了异常才改成了现在这样,如果这样的代码出现在你应用的各个角落,你慌不?

结论

方案1的处理和具体的代码绑定的比较死,依靠一堆判断来完成赋值,那么我们想到可以利用反射来完成对属性的赋值,这样字段再多,也不怕啦。

方案二

利用反射,通过mysql字段的名称,直接反射找到对应属性的set方法,执行调用。简单的代码如下所示。

Class<?> clazz = Class.forName("po.CityPO");
Object obj = clazz.newInstance();
for (int i = 1; i <= cols; i++) {
    Field field = null;
    field = clazz.getDeclaredField(meta.getColumnName(i));
    field.setAccessible(true);
    field.set(obj, resultSet.getObject(i));
}
cityPOS.add((CityPO) obj);

这段我为了测试,是直接把对应的对象的属性名改成了数据库中的列名。

缺点
  1. 因为是通过数据库的列名反射出对应的方法,而通常我们在Java中使用的是驼峰命名,怎么处理列名到对象类名的转换,这里应该有一定的代码量,当然也可以在select的时候 as成对应的属性名,这样就解决了这个问题。
  2. 我们依然需要处理类型转换。
  3. 我们可能会多选了一些列,而这个方案会统统去找反射的方法,可能会抛出异常。
结论

我觉得这应该是框架会采取的方案。

总结

直接用原生的JDBC完成数据库到Java业务对象的转换,肯定是非常繁琐的,从目前来看,框架应该也是用的方案2,只不过会比方案案强大的多。

从使用Mybatis这一段时间来看,其在这个方案做了这么几件事。

  1. 解决了数据库列名到Java列名的映射。
  2. 解决了数据库类型到Java类型的转换工作。
  3. 在转换过程中具备一定的容错能力。

后续

后续会研究下Mybatis在这方面所做的工作和源码,有兴趣可以持续关注我的微信公众号。

图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值