jdbc实现类mybatis结果集解析

Jdbc 比较繁琐的一个操作就是解析结果集ResultSet, 在实际开发时, 通常会将对结果集的解析封装为一个工具类. 需要注意的时, jdbc查询出来的属性可能不能直接转换为java的类型, 比如说java.sql.Date, 不能直接转换为java.util.Date 或LocalDate等类型, 需要自定义转换器. 如果比较熟悉Mybatis的话, 会发现Mybatis底层也封装了大量的类型转换器.

1. 工具类源码

笔者的工具类比较简单, 只封装了三个方法:

方法签名 方法描述 参数说明

public static LinkedHashMap<String, Object> toPropertyMap(ResultSet resultSet) throws SQLException 转换单行结果集为Map结构. key为列别名, value为列值 resultSet: 查询结果集

public static T toBean(ResultSet resultSet, Class clz) 转换结果集为单行对象 clz: 目标对象类型

resultSet: 结果集

public static List toBeans(ResultSet resultSet, Class clz) throws SQLException 转换结果集为java对象集合. clz: 要转换的javaBean类

resultSet: 结果集

1.1 ResultSetUtil 源码

/** 结果集解析工具类

* @since 1.0

* @author zongf

* @created 2019-07-18

*/

public class ResultSetUtil {

    /** 转换单行结果集为Map结构. key为列别名, value为列值

    * @param resultSet 查询结果集

    * @return 结果集中为空时, 返回null

    * @since 1.0

    * @author zongf

    * @created 2019-07-18

    */

    public static LinkedHashMap<String, Object> toPropertyMap(ResultSet resultSet) throws SQLException {

        // 如果结果集为空,则返回null

        if (!resultSet.next()) return null;

        LinkedHashMap<String, Object> cloumnMap = new LinkedHashMap<>();

        // 获取结果集元信息

        ResultSetMetaData metaData = resultSet.getMetaData();

        // 获取每一列列名与值

        for (int i = 1; i <= metaData.getColumnCount(); i++) {

            // 获取列别名为key

            String columnLabel = metaData.getColumnLabel(i);

            Object columnValue = resultSet.getObject(i);

            cloumnMap.put(columnLabel, columnValue);

        }

        return cloumnMap;

    }

    /** 转换结果集为单行对象

    * @param clz      目标对象类型

    * @param resultSet 结果集

    * @since 1.0

    * @return null

    * @author zongf

    * @created 2019-07-18

    */

    public static <T> T toBean(ResultSet resultSet, Class<T> clz) {

        try {

            LinkedHashMap<String, Object> propertyMap = toPropertyMap(resultSet);

            return ReflectUtil.newInstance(clz, propertyMap, new DateTypeConverter());

        } catch (SQLException e) {

            throw new RuntimeException("sql 执行异常!", e);

        }

    }

    /** 转换结果集为java对象集合.

    * @param clz      要转换的javaBean类

    * @param resultSet 结果集

    * @return 结果集中没有数据时, 返回null

    * @since 1.0

    * @author zongf

    * @created 2019-07-18

    */

    public static <T> List<T> toBeans(ResultSet resultSet, Class<T> clz) throws SQLException {

        List<T> list = new ArrayList<>();

        LinkedHashMap<String, Object> propertyMap = null;

        // 解析结果集

        while ((propertyMap = toPropertyMap(resultSet)) != null) {

            T t = (T) ReflectUtil.newInstance(clz, propertyMap, new DateTypeConverter());

            if(t != null) list.add(t);

        }

        return list.size() > 0 ? list : null;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

1.2 ReflectUtil 源码

这是笔者对使用到的反射技术封装的一个简单工具类.

/** 反射工具类

* @since 1.0

* @author zongf

* @created 2019-07-18

*/

public class ReflectUtil {

    /**为对象属性赋值

    * @param target 目标对象

    * @param property 属性名

    * @param property 属性名

    * @return value 属性值

    * @since 1.0

    * @author zongf

    * @created 2019-07-18

    */

    public static void setPropertyValue(Object target, String property, Object value) {

        try {

            PropertyDescriptor descriptor = new PropertyDescriptor(property, target.getClass());

            Method writeMethod = descriptor.getWriteMethod();

            writeMethod.invoke(target, value);

        } catch (Exception e) {

            throw new RuntimeException("为对象属性赋值异常!",e);

        }

    }

    /** 获取对象属性值

    * @param target 目标对象

    * @param property 属性

    * @return Object 返回对象属性值

    * @since 1.0

    * @author zongf

    * @created 2019-07-18

    */

    public static Object getPropertyValue(Object target, String property) {

        try {

            PropertyDescriptor descriptor = new PropertyDescriptor(property, target.getClass());

            Method readMethod = descriptor.getReadMethod();

            return readMethod.invoke(target);

        } catch (Exception e) {

            throw new RuntimeException("获取对象属性异常!",e);

        }

    }

    /** 反射创建对象

    * @param clz 目标对象的类型

    * @return propertiesMap 目标对象的属性与值

    * @since 1.0

    * @author zongf

    * @created 2019-07-18

    */

    public static <T> T newInstance(Class<T> clz, HashMap<String, Object> propertiesMap, DateTypeConverter typeConverter){

        // 如果属性为空, 则不进行创建, 返回null

        if (propertiesMap == null || propertiesMap.isEmpty()) {

            return null;

        }

        // 使用无参数构造方法创建对象

        T t = null;

        try {

            t = clz.newInstance();

            for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {

                // 获取对象属性与值

                String property = entry.getKey();

                Object value = entry.getValue();

                // 获取属性描述符

                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, clz);

                // 获取属性类型

                Class<?> propertyType = propertyDescriptor.getPropertyType();

                // 使用类型转换器转换参数类型

                value = typeConverter.convert(value, propertyType);

                // 调用set方法, 赋值

                Method writeMethod = propertyDescriptor.getWriteMethod();

                writeMethod.invoke(t, value);

            }

        } catch (Exception e) {

            throw new RuntimeException("反射创建对象失败!", e);

        }

        return t;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

1.3 DateTypeConverter 转换器

笔者仅仅编写了一个日期类型的转换器, 在企业开发中, 可能需要用到的转换器会更多.

/** 日期类型转换器

* @since 1.0

* @author zongf

* @created 2019-07-18

*/

public class DateTypeConverter {

    /** 转换对象的类型

    * @param value 值

    * @param javaType java类型

    * @return 转换后的类型

    * @since 1.0

    * @author zongf

    * @created 2019-07-18

    */

    public Object convert(Object value, Class javaType) {

        Object obj = value;

        // 如果是java 日期

        if(javaType.equals(Date.class)) {

            java.sql.Date date = (java.sql.Date) value;

            obj = date.toInstant().getEpochSecond();

            // 如果是java8 日期

        } else if(javaType.equals(LocalDate.class)){

            obj = ((java.sql.Date) value).toLocalDate();

        } else {

            obj = value;

        }

        return obj;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

2. 单元测试

2.1 创建javaBean

测试时, 需要创建t_user表和javabean, 笔者这边仅给出javabean的定义.

public class UserPO {

    private Integer id;

    private String name;

    private String password;

   

    private LocalDate birthday;

   

    // 省略setter/getter/toString 方法

   

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

2.2 测试用例

// 测试转换单个对象为Map 结构

@Test

public void toPropertyMap() throws SQLException {

    String str = "select id uId, name , pwd, birthday from t_user where id = 1001";

    Connection connection = DbConnUtil.getConnection(true);

    Statement statement = connection.createStatement();

    ResultSet resultSet = statement.executeQuery(str);

    LinkedHashMap<String, Object> map = ResultSetUtil.toPropertyMap(resultSet);

    map.forEach((key, val) -> System.out.println(key + ":" + val));

}

// 测试转换对象为单个bean

@Test

public void toBean() throws SQLException {

    String str = "select * from t_user where id = 1002";

    Connection connection = DbConnUtil.getConnection(true);

    Statement statement = connection.createStatement();

    ResultSet resultSet = statement.executeQuery(str);

    UserPO userPO = ResultSetUtil.toBean(resultSet, UserPO.class);

    System.out.println(userPO);

}

// 测试转换对象为bean列表

@Test

public void toBeans() throws SQLException {

    String str = "select * from t_user ";

    Connection connection = DbConnUtil.getConnection(true);

    Statement statement = connection.createStatement();

    ResultSet resultSet = statement.executeQuery(str);

    List<UserPO> userPOList = ResultSetUtil.toBeans(resultSet, UserPO.class);

    userPOList.forEach(System.out::println);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 一. Java基础部分.................................................
    wy_sure阅读 3,774评论 0 11
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,243评论 0 16
  • 本节介绍Statement接口及其子类PreparedStatement和CallableStatement。 它...
    zlb阅读 1,110评论 0 0
  • 《钱本草》——张说 钱,味甘,大热,有毒。偏能驻颜,采泽流润,善疗饥,解困厄之患立验。能利邦国,亏贤达,畏...
    72e518839e4c阅读 1,222评论 0 1
  • 月儿,冷空气突然降临 渴望雪,滋润干枯的日子 却听见彼此在瞬间碎去的声音,沉重落地 携带钻入内心的冰冷,刺入骨髓 ...
    杨昊田阅读 416评论 59 50