提出問題
JDBC 中查詢的資料存盤在 ResultSet 中,一般來說,需要有一個物體類來承載 ResultSet 的資料,比如,資料庫有一個 users 表,查詢出來的結果肯定是要注入到 User 物體類中的,
一般的做法就是通過 while 遍歷 ResultSet,通過getString()(或其他對應型別的 getter)注入到物體類中(物體類的 setter),難道每一個表的查詢都要重新寫一個重復的注入物體類的操作代碼嗎?通過反射機制我們可以簡化這樣的操作,
問題案例
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;
}
如果是 Student 物體類,那么 while 體內的代碼又要修改,十個不同的物體類就修改十次,并且欄位又多,太麻煩!
通過反射解決問題
最重要的是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);
} 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()));
}
不管物體類欄位有多少個,都不需要一個個去 setter 和 getter,這樣做起來簡直太方便了,而且,因為使用了泛型,物體類的型別也是可以改變的,比如說查詢的表是 students,那么把型別換成 Student 就可以了,

補充說明
在測驗函式中,new LoadConfig<>(MySQLConfig.class).getConfig()是我寫的一個方便配置資料庫的配置加載工具類,具體實踐我在另一篇隨筆中有:注解帶來的好處,注解如何簡化代碼,
這里是??GitHub 倉庫的原始碼地址,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/517505.html
標籤:Java
