欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

反射简化 JDBC ResultSet,比如,数据库user

来源: javaer 分享于  点击 41194 次 点评:175

反射简化 JDBC ResultSet,比如,数据库user


提出问题

查询完某个表之后,一般都是把结果的每一个字段注入到一个实体类中。比如,数据库 users 表,查询出来的结果注入到 User 实体类中。

通过 while 遍历 ResultSet,把字段对应的类型通过对应的方法getXxx()注入到实体类中。每一个实体类的字段都不一样,又重新写重复的注入实体类的操作代码,是非常麻烦的,幸好有反射机制可以简化这样的操作。

问题案例

public List<User> selectAll() {
  List<User> users = new ArrayList<>();
  try {
    Connection connection = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword());
    PreparedStatement statement = connection.prepareStatement("select * from users");
    ResultSet rs = statement.executeQuery();
    while (rs.next()) {
      User user = new User();
      user.setId(rs.getInt("id"));
      user.setAge(rs.getInt("age"));
      user.setAvatar(rs.getString("avatar"));
      user.setShow_name(rs.getString("show_name"));
      users.add(user);
    }
  } catch (SQLException e) {
    throw new RuntimeException(e);
  }
  return users;
}

students 表的查询结果,注入数据到 Student 实体类中。users 表,又得写差不多的重复代码,也只是 new 实体类以及循环体内的注入代码发生了变化。

通过反射解决问题

jnject专门来处理如何把 ResultSet 结果注入到实体类中。需要传递一个实体类的反射对象,类型是泛型:

private List<T> inject(ResultSet rs, Class<T> clz) {
  List<T> list = new ArrayList<>();
  try {
    while (rs.next()) {
      T t = clz.getDeclaredConstructor().newInstance();
      for (Field field : clz.getDeclaredFields()) {
        field.setAccessible(true);
        if (field.getType().getName().equals(String.class.getName())) {
          field.set(t, rs.getString(field.getName()));
        } else if (field.getType().getName().equals(int.class.getName())) {
          field.set(t, rs.getInt(field.getName()));
        } else if (field.getType().getName().equals(java.util.Date.class.getName())) {
          field.set(t, rs.getDate(field.getName()));
        }
      }
      list.add(t);
    }
  } catch (SQLException | InvocationTargetException | InstantiationException | IllegalAccessException |
           NoSuchMethodException e) {
    throw new RuntimeException(e);
  }
  return list;
}

通过反射创建实体类对象,再获取这个实体类对象的所有字段,不管你是 private、public、protected 修饰的字段都可以获取,所以,必须通过getDeclaredFields()函数来获取对象的字段。

在 for 循环体中,我做了一个判断,判断实体类字段的类型是什么类型,针对类型去从结果集中获取相应类型的值,再通过 Field 对象的set函数给实体类的属性注入值。

public List<T> selectAll(Class<T> clz) {
  List<T> list;
  try {
    Connection connection = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword());
    PreparedStatement statement = connection.prepareStatement("select * from users");
    list = inject(statement.executeQuery(), clz); // 调用 inject 函数,完成实体类注入
  } catch (SQLException e) {
    throw new RuntimeException(e);
  }
  return list;
}

测试函数

public static void main(String[] args) {
  MySQLConfig config = new LoadConfig<>(MySQLConfig.class).getConfig();
  List<User> users = new Simple<User>(config).selectAll(User.class);
  System.out.println(Arrays.toString(users.toArray()));
}

在使用层面上,我们无需再关注如何把结果集注入到实体类中,而只需要提供一个实体类的反射对象即可完成查询操作。

补充说明

在测试函数中,new LoadConfig<>(MySQLConfig.class).getConfig()是我写的一个方便配置数据库的配置加载工具类。具体实践我在另一篇随笔中有:注解带来的好处,注解如何简化代码。

这里是

相关文章

    暂无相关文章
相关栏目:

用户点评