1. 程式人生 > 其它 >成員變數命名不規範導致的錯誤 Class has no flields;

成員變數命名不規範導致的錯誤 Class has no flields;

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,在解析過程會按照對待類的方式去解析,

而存在兩種情況 ,具體是哪一個有待測試;

  1. 無法正常執行metaData.getColumnCount();

  2. 無法使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);

    }
}