成員變數命名不規範導致的錯誤 Class has no flields;
阿新 • • 發佈:2021-07-01
JDBC 對映資料庫時成員變數命名不規範導致的bug //未完待續,待補充測試資訊;
JDBC連線資料庫時,用新建的實體類去對映資料庫中表資訊,因為命名不規範,導致輸出結果始終為空;
期間解析過程正常,新增過程正常
對映類:
public class Dep { private Integer Did; private String Dname; public Dep() { } public Dep(Integer did, String dname) { this.Did = did; this.Dname=dname; }
屬性Did對映資料庫中的表dep的欄位Did,在解析多行內容時會將其打包成鍵值對物件新增到list中;
這裡的錯誤是:成員變數did的首字母大寫 Did,在解析過程會按照對待類的方式去解析,
而存在兩種情況 ,具體是哪一個有待測試;
無法正常執行metaData.getColumnCount();
無法使getDecalerdField方法成功獲得到欄位;
程式碼:
第一部分:封裝一個工具類
package util; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; public class BaseDao { /** * 通用 Update 方法,用於處理 insert, delete, update SQL語句操作。 * * @param sql 執行所需的SQL語句,字串型別 * @param parameters 針對當前SQL語句引數列表,為Object型別,不定長引數 * @return 當前SQL語句操作,對資料表的影響行數。 */ public int update(String sql, Object... parameters) { // 1. 操作 SQL 語句必備變數準備和資料庫連線物件獲取 PreparedStatement statement = null; Connection connection = JdbcUtils.getConnection(); int affectedRows = 0; // 2. 判斷使用者給予當前方法 SQL 是否為null if (null == sql || sql.isEmpty()) { // 非法引數異常 throw new IllegalArgumentException("SQL語句引數不合法"); } try { // 3. 預處理SQL語句,得到PreparedStatement物件 statement = connection.prepareStatement(sql); // 4. 賦值引數 assignSqlParameters(statement, parameters); // 5. 執行SQL語句 affectedRows = statement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.close(connection, statement); } return affectedRows; } /** * 用於滿足通用查詢操作的 query方法,指定使用者給予的SQL語句,對應引數已經整個資料行對應的 * 資料型別,轉換為 List集合返回。 * tips: 當前操作有且只能針對 類物件型別,不得用於基本型別查詢操作。 * * @param sql String SQL 語句 * @param cls 當前資料行對映對應的型別 Class型別【ROM思想 關係 物件 對映】 * @param parameters 對應當前SQL語句引數 * @param <T> 自定義泛型無意義佔位符 * @return 儲存使用者指定資料型別的List集合,如果沒有資料查詢結果,返回null */ public <T> List<T> query(String sql, Class<T> cls, Object... parameters) { // 1. 判斷用於給予當前方法引數是否合適 if (null == sql || sql.isEmpty() || null == cls) { throw new IllegalArgumentException("給予當前query方法引數不合法"); } // 2. 準備資料庫操作必要內容 ResultSet resultSet = null; PreparedStatement statement = null; Connection connection = JdbcUtils.getConnection(); List<T> list = new ArrayList<>(); try { // 3. 預處理SQL語句,得到PreparedStatement物件 statement = connection.prepareStatement(sql); // 4. SQL語句引數賦值操作 assignSqlParameters(statement, parameters); // 5. 執行SQL 語句 得到ResultSet結果集物件 resultSet = statement.executeQuery(); // 6. 獲取結果集元資料 ResultSetMetaData metaData = resultSet.getMetaData(); // 7. 通過結果集元資料獲取對應的欄位個數 int columnCount = metaData.getColumnCount(); // 8. 解析資料 while (resultSet.next()) { // 每一行資料對應一個類物件,當前類物件需要通過反射方式進行建立 T object = cls.getConstructor().newInstance(); // 解析欄位資料 ==> 成員變數 for (int i = 1; i <= columnCount; i++) { // 獲取欄位名稱 ==> 成員變數名 String columnName = metaData.getColumnName(i); // 獲取對應欄位 String 資料 String value = resultSet.getString(columnName); setProperty(object, columnName, value); } list.add(object); } } catch (SQLException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) { e.printStackTrace(); } return list.size() != 0 ? list : null; } private void assignSqlParameters(PreparedStatement statement, Object[] parameters) throws SQLException { // 4.1 獲取 SQL 語句預處理物件元資料,得到引數個數 int parameterCount = statement.getParameterMetaData().getParameterCount(); // 4.2 判斷引數陣列資料個數 和當前 parameterCount 引數個數是否一致 if (parameterCount != 0 && parameters.length == parameterCount) { for (int i = 0; i < parameterCount; i++) { statement.setObject(i + 1, parameters[i]); } } } /** * 私有化類內使用方法,用於處理指定類物件,指定成員變數名稱,以及對應當前成員變數String型別資料,賦值 * 轉換過程。 * * @param o 符合JavaBean規範類物件。 * @param fieldName 指定成員變數名稱 * @param value 對應當前成員變數 String型別賦值資料 */ private void setProperty(Object o, String fieldName, String value) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { // 1. 根據欄位名稱獲取對應的Field類物件 Field declaredField = o.getClass().getDeclaredField(fieldName); declaredField.setAccessible(true); // 2. 獲取當前成員變數對應資料型別 Integer ==> parseInt Class<?> type = declaredField.getType(); // 3. 判斷當前資料型別,進行賦值操作 if (type.equals(Integer.class)) { declaredField.set(o, Integer.parseInt(value)); } else if (type.equals(Character.class)) { declaredField.set(o, value.charAt(0)); } else if (type.equals(String.class)) { declaredField.set(o, value); } else { // java.lang.Long ==> "Long" String typeName = type.getName().substring(type.getName().lastIndexOf('.') + 1); // 找出parseLong(String) Method method = type.getMethod("parse" + typeName, String.class); // method是對應的parseLong方法,value是對應需要進行的String型別資料,因為parse方法都是static方法 // 執行操作無需類物件,直接null即可 declaredField.set(o, method.invoke(null, value)); } } }
第二部分:測試方法:呼叫query查詢資料庫表內容;
package newpackage1; import Util.BaseDao2; import java.lang.reflect.InvocationTargetException; import java.sql.SQLException; public class test7ForQuery extends BaseDao2 { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException { BaseDao2 baseDao2 = new BaseDao2(); baseDao2.query("select * from javaee2106.dep where Did <?",Dep.class,5); } }