提出问题

查询完某个表之后,一般都是把结果的每一个字段注入到一个实体类中。比如,数据库 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()是我写的一个方便配置数据库的配置加载工具类。具体实践我在另一篇随笔中有:注解带来的好处,注解如何简化代码

这里是GitHub 仓库的源码地址。

最新文章

  1. IIS 连接 oracle报Oracle.DataAccess版本错误解决办法
  2. osgi 2
  3. Python生成二维码脚本
  4. 解决log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader)警告信息的问题
  5. Oracle 数据库 Database Express Edition 11g Release 2 (11.2) 错误解决集锦(使用语法)
  6. Qt编程之对QGraphicsItem点击右键弹出菜单
  7. cocos2d js 怎样动态载入外部图片
  8. make -j 多核并行编译 导致笔记本过热 自动关机保护
  9. Errors occurred during the build. Errors running builder &#39;JavaScript Validator&#39; on project &#39;项目名&#39;.
  10. docker部署express应用
  11. ASP.NET Core中使用Autofac
  12. IE6下select被这罩住
  13. Linux 下 mysql的基本配置
  14. 图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)
  15. 奇妙的 CSS shapes(CSS图形) 【css 图形,绘图,CSS 几何图形)】
  16. 剑指offer:矩形覆盖
  17. lintcode-488-快乐数
  18. linux 内核信号量
  19. &lt;转&gt;jmeter JDBC Request之Query Type
  20. tomcat运行报错Failed to start component [StandardEngine[Catalina].StandardHost[localhost].

热门文章

  1. 快速入门JavaScript编程语言
  2. Vuex极速入门
  3. nuxt.js框架 如何打包 build
  4. Mybatis-9.28
  5. django中只使用ModleForm的表单验证,而不使用ModleForm来渲染
  6. BFS广度优先搜索例题分析
  7. ssm——mybatis整理
  8. 既然有MySQL了,为什么还要有MongoDB?
  9. TiDB 底层存储结构 LSM 树原理介绍
  10. 《STL源码剖析》traits技法分析