资讯专栏INFORMATION COLUMN

【JDBC系列】JDBC原生处理ResultSet

Warren / 2931人阅读

摘要:背景最近在学习,在处理返回值与业务对象之间的转换非常方便,定义,标明互相之间的转换关系,即可轻松完成转换。我们会写使用原生的来获取返回值。

背景

最近在学习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 cityPOS = new ArrayList();
对象转换

我们要完成的工作就是将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);
    }
}
缺点

转换完全和具体的业务类绑定在了一起,你如果新处理一个业务类,你得再重新写一套差不多的代码,而且随着类的属性字段的增多,你的if/else代码会越来越多,听起来是不是很恐怖。

在调用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);

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

缺点

因为是通过数据库的列名反射出对应的方法,而通常我们在Java中使用的是驼峰命名,怎么处理列名到对象类名的转换,这里应该有一定的代码量,当然也可以在select的时候 as成对应的属性名,这样就解决了这个问题。

我们依然需要处理类型转换。

我们可能会多选了一些列,而这个方案会统统去找反射的方法,可能会抛出异常。

结论

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

总结

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

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

解决了数据库列名到Java列名的映射。

解决了数据库类型到Java类型的转换工作。

在转换过程中具备一定的容错能力。

后续

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67417.html

相关文章

  • 谈谈Spring-Data的那些事儿

    摘要:什么是呢全称,是提出的一个对象持久化规范,各应用服务器自主选择具体实现。仅仅只是一个规范,而不是产品使用本身是不能做到持久化的。只要提供了持久化类与表的映射关系,框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。 我们在进行事务处理往往需要和数据库进行交互,这其中有关系型数据库(MySql,Sql Server,Oracle)或者是非关系型数据库(Redis,Hadhoop)...

    chinafgj 评论0 收藏0
  • 谈谈Spring-Data的那些事儿

    摘要:什么是呢全称,是提出的一个对象持久化规范,各应用服务器自主选择具体实现。仅仅只是一个规范,而不是产品使用本身是不能做到持久化的。只要提供了持久化类与表的映射关系,框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。 我们在进行事务处理往往需要和数据库进行交互,这其中有关系型数据库(MySql,Sql Server,Oracle)或者是非关系型数据库(Redis,Hadhoop)...

    charles_paul 评论0 收藏0
  • JDBC系列】从源码角度理解JDBC和Mysql的预编译特性

    摘要:我们对语句做适当改变,就完成了注入,因为普通的不会对做任何处理,该例中单引号后的生效,拉出了所有数据。查询资料后,发现还要开启一个参数,让端缓存,缓存是级别的。结论是个好东西。 背景 最近因为工作调整的关系,都在和数据库打交道,增加了许多和JDBC亲密接触的机会,其实我们用的是Mybatis啦。知其然,知其所以然,是我们工程师童鞋们应该追求的事情,能够帮助你更好的理解这个技术,面对问题...

    longshengwang 评论0 收藏0

发表评论

0条评论

Warren

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<