1. 程式人生 > 其它 >idea中出現sql語句錯誤提示:【the right syntax to use near ‘‘ 】的解決方法

idea中出現sql語句錯誤提示:【the right syntax to use near ‘‘ 】的解決方法

記錄一下這個坑,這是一個有關idea顯示問題導致無法檢查出錯誤的坑

idea中報錯資訊

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1

我的錯誤程式碼

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.lang.reflect.*; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; /** * 該類使用約束: * 表名及欄位名等要與相應POJO一致 * 但是表名及欄位名等單詞用下劃線分隔,而POJO中類名(即代表的關係名、表名)使用大坨峰, * 而成員屬性名(即欄位名)使用小駝峰 * * @param <T> 所要操作POJO型別 */
public class JdbcUtils<T> { public static String driver = null; //資料庫驅動 public static String url = null; //資料庫地址 public static String user = null;//資料庫使用者 public static String password = null;//資料庫使用者密碼 public static HashMap<Class<?>, Method> ptmtMap = new HashMap<
>();//PrepareStatement設定sql中?內容的【屬性型別】到【相應方法】的對映 public static HashMap<Class<?>, Method> rsMap = new HashMap<>();//ResultSet中獲取sql執行結果集中每條記錄的【相應欄位】到【相應方法】的對映 public static HashMap<Class<?>, Class<?>> primaryClassMap = new HashMap<>();//設定基本型別到原始型別的轉換 private String sql = null; //執行的sql語句 private Connection conn = null;//資料庫連線物件 private Statement stmt = null;//資料庫執行物件 private PreparedStatement ptmt = null;//資料庫執行物件 private ResultSet rs = null;//資料庫執行結果集 private Integer rowCount = null; // 表示執行executeUpdate方法時的返回值,代表改動的記錄數(即行數) private boolean isExecute = false; // 表示執行execute方法時的返回值,若執行成功則為true,否則為false /** * 用於載入資料庫驅動 */ private static void loadDriver() { try { // 讀取資料庫配置檔案 FileInputStream fis = new FileInputStream("D:\\ideaProject\\javaweb-maven\\jdbcUtils\\src\\main\\resources\\jdbc.properties"); Properties properties = new Properties(); properties.load(fis); fis.close(); driver = properties.getProperty("jdbc.driver"); url = properties.getProperty("jdbc.url"); user = properties.getProperty("jdbc.user"); password = properties.getProperty("jdbc.password"); Class.forName(driver); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 【各種型別】與【PrepareStatement中設定方法】所對應的HashMap關係表 */ private static void setPtmtMap(PreparedStatement ptmt) { Class<PreparedStatement> ptmtClass = (Class<PreparedStatement>) ptmt.getClass(); Method[] methods = ptmtClass.getMethods(); String pattern = "^set[A-Z][\\w]*";//使用過濾不是設定sql語句問號內容的方法的正則表示式 for (Method method : methods) { String methodName = method.getName(); boolean isMatch = Pattern.matches(pattern, methodName); if (!isMatch) continue; if (method.getParameterCount() != 2)//該工具只用【設定sql語句問號內容】只有2個引數的方法 continue; Class[] classes = method.getParameterTypes(); String className = classes[1].getSimpleName(); if (methodName.equalsIgnoreCase("set" + className)) //進一步判斷是否為setXxxx方法 ptmtMap.put(classes[1], method); } } /** * 【各種型別】與【ResultSet中獲取方法】所對應的HashMap關係表 */ private static void setRsMap(PreparedStatement ptmt) { try { Class<ResultSet> rsClass = (Class<ResultSet>) ptmt.executeQuery().getClass(); Method[] methods = rsClass.getMethods(); String pattern = "^get[A-Z][\\w]*";//通過獲取欄位方法名稱中開頭都含有【getX】規律, // 設定過濾不是獲取查詢結果欄位值的方法的正則表示式 for (Method method : methods) { String methodName = method.getName(); boolean isMatch = Pattern.matches(pattern, methodName); if (!isMatch) continue; if (method.getParameterCount() != 1)//進一步過濾,由於獲取欄位方法通常只有1個形參 continue; Class returnType = method.getReturnType(); rsMap.put(returnType, method);//根據方法的返回值建立對映 } } catch (SQLException e) { e.printStackTrace(); } } private static void setPrimaryClassMap() { primaryClassMap.put(Integer.class, int.class); primaryClassMap.put(Double.class, double.class); primaryClassMap.put(Float.class, float.class); } static { loadDriver(); Connection conn = null; PreparedStatement ptmt = null; try { conn = DriverManager.getConnection(url, user, password); ptmt = conn.prepareStatement("select database()"); setPtmtMap(ptmt); setRsMap(ptmt); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ptmt != null) { try { ptmt.close(); } catch (SQLException e) { e.printStackTrace(); } } } setPrimaryClassMap(); } public JdbcUtils() { } /** * 連線資料庫 * * @return 若成功返回true,否則返回false */ public boolean connect() { try { conn = DriverManager.getConnection(url, user, password); } catch (SQLException e) { e.printStackTrace(); } return conn != null; } /** * 按封裝好的POJO物件查詢條件,執行查詢操作 * * @param obj 封裝好的查詢條件 * @return 查詢後的ArrayList結果集 */ public List<T> ptmtQuery(T obj) { sql = "select * from "; String classSimpleName = obj.getClass().getSimpleName(); sql += toStdName(classSimpleName); if (!addCondition(obj) || !setQuestionMarkContent(1, obj)) { return null; } try { System.out.println(sql); rs = ptmt.executeQuery(); // rs = ptmt.executeQuery("select * from student where 1=1 and id=1 and age=18"); } catch (SQLException e) { e.printStackTrace(); } return toArrayList(); } /** * @param index 所設定問號開始的下標 * @param obj 問號設定的內容,要封裝成POJO物件 * @return 若設定成功返回true,否則返回false */ public boolean setQuestionMarkContent(int index, T obj) { try { ptmt = conn.prepareStatement(sql); } catch (SQLException e) { e.printStackTrace(); } Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); Object fieldValue = field.get(obj); if (fieldValue == null) continue; Class<?> fieldClass = field.getType(); if (primaryClassMap.get(fieldClass) != null) { fieldClass = primaryClassMap.get(fieldClass); } Method method = ptmtMap.get(fieldClass); method.invoke(ptmt, index++, fieldValue); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); return false; } } return true; } /** * 給當前sql語句新增查詢或者刪除、修改的條件。即“where XXX” * * @param obj 條件封裝成的POJO物件 * @return 若設定成功返回true,否則返回false */ public boolean addCondition(T obj) { Class tClass = obj.getClass(); Field[] declaredFields = tClass.getDeclaredFields(); sql += " where 1=1"; for (Field field : declaredFields) { String key = toStdName(field.getName()); field.setAccessible(true); try { if (field.get(obj) != null) { sql += " and " + key + "=?"; } } catch (IllegalAccessException e) { e.printStackTrace(); return false; } } return true; } /** * 將資料庫中的表名、欄位名等轉換為規定的名字 * * @param name 表名(即關係名) * @return 修改後的名字 */ public String toStdName(String name) { char[] nameChars = name.toCharArray(); char[] s = new char[name.length() * 2]; int len = 0; if (nameChars.length > 0) { if ((nameChars[0] & 0x20) != 0) //通過ASCII碼規律,判斷是否為大小寫 s[len++] = nameChars[0]; else s[len++] = (char) (nameChars[0] + 32);//轉換為小寫 } for (int i = 1; i < nameChars.length; i++) { char c = nameChars[i]; if ((c & 0x20) != 0) { //通過ASCII碼規律,判斷是否為大小寫 s[len++] = c; } else { s[len++] = '_'; s[len++] = (char) (c + 32);//轉換為小寫 } } s[len] = '\0'; return String.valueOf(s); } /** * 將結果集轉換為ArrayList<T>物件 * * @return 若成功,則返回結果集轉換的ArrayList<T>物件;否則返回null */ public List<T> toArrayList() { if (rs == null) return null; List<T> list = new ArrayList<>(); //獲取泛型的Class物件 Class<T> tClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; Constructor<T> constructor = null; Field[] fields = tClass.getDeclaredFields(); try { constructor = tClass.getConstructor(); while (rs.next()) { T obj = constructor.newInstance(); for (Field field : fields) { field.setAccessible(true); Method method = rsMap.get(field.getType()); Object value = method.invoke(rs, toStdName(field.getName())); field.set(obj, value); } list.add(obj); } } catch (SQLException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { e.printStackTrace(); return null; } return list; } }

我的測試程式碼

    @Test
    public void ptmtQuery() {
        JdbcUtils<Student> jdbcUtils = new JdbcUtils<>();
        Student stu = new Student(null, "小明", null, null);
        jdbcUtils.connect();
        System.out.println(jdbcUtils.ptmtQuery(stu));
    }

idea報錯完整資訊

"C:\Program Files\Java\jdk-12.0.1\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 -Didea.launcher.port=61892 "-Didea.launcher.bin.path=D:\Program Files (x86)\IntelliJ IDEA 2018.2.5\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files (x86)\IntelliJ IDEA 2018.2.5\lib\idea_rt.jar;D:\Program Files (x86)\IntelliJ IDEA 2018.2.5\plugins\junit\lib\junit-rt.jar;D:\Program Files (x86)\IntelliJ IDEA 2018.2.5\plugins\junit\lib\junit5-rt.jar;D:\ideaProject\javaweb-maven\jdbcUtils\target\test-classes;D:\ideaProject\javaweb-maven\jdbcUtils\target\classes;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\junit\junit\4.11\junit-4.11.jar;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\mysql\mysql-connector-java\8.0.23\mysql-connector-java-8.0.23.jar;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\com\google\protobuf\protobuf-java\3.11.4\protobuf-java-3.11.4.jar;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\javax\servlet\javax.servlet-api\4.0.1\javax.servlet-api-4.0.1.jar;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\javax\servlet\jsp\jsp-api\2.1\jsp-api-2.1.jar;D:\Program Files (x86)\webpage editing tools\apache-maven-3.5.4\repo\org\apache\taglibs\taglibs-standard-impl\1.2.5\taglibs-standard-impl-1.2.5.jar" com.intellij.rt.execution.application.AppMainV2 com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 JdbcUtilsTest,ptmtQuery
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)
	at JdbcUtils.ptmtQuery(JdbcUtils.java:173)
	at JdbcUtilsTest.ptmtQuery(JdbcUtilsTest.java:17)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
null
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)

Process finished with exit code 0

錯誤原因分析

idea一直報sql語法出現錯誤,但是通過除錯看到的情況如下:
在這裡插入圖片描述
可以明顯看出sql語法沒有出現錯誤,但是這只是被idea給欺騙了,idea在這裡顯示的字串是經過處理的。不信,可以複製sql變數的值到txt文字中,我們可以發現,貼上過去的字串顯示如下:
在這裡插入圖片描述
可以看到"student"和"student_name"兩個位置後面出現了很多空格,這是為什麼呢?
接下來,我們去看原始碼,就能知道問題的原因了
以上兩個位置的字串都是經過一個toStdName的方法處理後才拼接到sql變數中的,問題就出在這個toStdName方法

public String toStdName(String name) {
        char[] nameChars = name.toCharArray();
        char[] s = new char[name.length() * 2];
        int len = 0;
        if (nameChars.length > 0) {
            if ((nameChars[0] & 0x20) != 0) //通過ASCII碼規律,判斷是否為大小寫
                s[len++] = nameChars[0];
            else
                s[len++] = (char) (nameChars[0] + 32);//轉換為小寫
        }
        for (int i = 1; i < nameChars.length; i++) {
            char c = nameChars[i];
            if ((c & 0x20) != 0) {  //通過ASCII碼規律,判斷是否為大小寫
                s[len++] = c;
            } else {
                s[len++] = '_';
                s[len++] = (char) (c + 32);//轉換為小寫
            }
        }
        s[len] = '\0'; //此處設定結尾字元
        return String.valueOf(s); 
    }

問題就出在這裡

		s[len] = '\0'; //此處設定結尾字元
        return String.valueOf(s); //問題就出在這裡,字元陣列s的長度是原先傳進去的字串長度的兩倍,而String.valueOf這個方法雖然能將s陣列轉換為字串,但是它不會以設定的'\0'作為結尾,導致其長度為陣列長度,而不是為字串長度,而idea又出於某種原因,導致顯示的是以'\0'作為結尾的字串內容

又因為PrepareStatement的sql語句中不能出現多餘空格,所以導致sql語法報錯。結果在加上,idea的顯示問題,導致這個錯誤很難被發現,這真是一個坑

修改後的正確程式碼如下

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * 該類使用約束:
 * 表名及欄位名等要與相應POJO一致
 * 但是表名及欄位名等單詞用下劃線分隔,而POJO中類名(即代表的關係名、表名)使用大坨峰,
 * 而成員屬性名(即欄位名)使用小駝峰
 *
 * @param <T> 所要操作POJO型別
 */
public class JdbcUtils<T> {
    public static String driver = null; //資料庫驅動
    public static String url = null;    //資料庫地址
    public static String user = null;//資料庫使用者
    public static String password = null;//資料庫使用者密碼
    public static HashMap<Class<?>, Method> ptmtMap = new HashMap<>();//PrepareStatement設定sql中?內容的【屬性型別】到【相應方法】的對映
    public static HashMap<Class<?>, Method> rsMap = new HashMap<>();//ResultSet中獲取sql執行結果集中每條記錄的【相應欄位】到【相應方法】的對映
    public static HashMap<Class<?>, Class<?>> primaryClassMap = new HashMap<>();//設定基本型別到原始型別的轉換
    private String sql = null; //執行的sql語句
    private Connection conn = null;//資料庫連線物件
    private Statement stmt = null;//資料庫執行物件
    private PreparedStatement ptmt = null;//資料庫執行物件
    private ResultSet rs = null;//資料庫執行結果集
    private Integer rowCount = null;   // 表示執行executeUpdate方法時的返回值,代表改動的記錄數(即行數)
    private boolean isExecute = false; // 表示執行execute方法時的返回值,若執行成功則為true,否則為false

    /**
     * 用於載入資料庫驅動
     */
    private static void loadDriver() {
        try {
//            讀取資料庫配置檔案
            FileInputStream fis = new FileInputStream("D:\\ideaProject\\javaweb-maven\\jdbcUtils\\src\\main\\resources\\jdbc.properties");
            Properties properties = new Properties();
            properties.load(fis);
            fis.close();
            driver = properties.getProperty("jdbc.driver");
            url = properties.getProperty("jdbc.url");
            user = properties.getProperty("jdbc.user");
            password = properties.getProperty("jdbc.password");
            Class.forName(driver);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 【各種型別】與【PrepareStatement中設定方法】所對應的HashMap關係表
     */
    private static void setPtmtMap(PreparedStatement ptmt) {
        Class<PreparedStatement> ptmtClass = (Class<PreparedStatement>) ptmt.getClass();
        Method[] methods = ptmtClass.getMethods();
        String pattern = "^set[A-Z][\\w]*";//使用過濾不是設定sql語句問號內容的方法的正則表示式
        for (Method method : methods) {
            String methodName = method.getName();
            boolean isMatch = Pattern.matches(pattern, methodName);
            if (!isMatch)
                continue;
            if (method.getParameterCount() != 2)//該工具只用【設定sql語句問號內容】只有2個引數的方法
                continue;
            Class[] classes = method.getParameterTypes();
            String className = classes[1].getSimpleName();
            if (methodName.equalsIgnoreCase("set" + className)) //進一步判斷是否為setXxxx方法
                ptmtMap.put(classes[1], method);
        }
    }

    /**
     * 【各種型別】與【ResultSet中獲取方法】所對應的HashMap關係表
     */
    private static void setRsMap(PreparedStatement ptmt) {
        try {
            Class<ResultSet> rsClass = (Class<ResultSet>) ptmt.executeQuery().getClass();
            Method[] methods = rsClass.getMethods();
            String pattern = "^get[A-Z][\\w]*";//通過獲取欄位方法名稱中開頭都含有【getX】規律,
            // 設定過濾不是獲取查詢結果欄位值的方法的正則表示式
            for (Method method : methods) {
                String methodName = method.getName();
                boolean isMatch = Pattern.matches(pattern, methodName);
                if (!isMatch)
                    continue;
                if (method.getParameterCount() != 1)//進一步過濾,由於獲取欄位方法通常只有1個形參
                    continue;
                Class returnType = method.getReturnType();
                rsMap.put(returnType, method);//根據方法的返回值建立對映
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static void setPrimaryClassMap() {
        primaryClassMap.put(Integer.class, int.class);
        primaryClassMap.put(Double.class, double.class);
        primaryClassMap.put(Float.class, float.class);
    }

    static {
        loadDriver();
        Connection conn = null;
        PreparedStatement ptmt = null;
        try {
            conn = DriverManager.getConnection(url, user, password);
            ptmt = conn.prepareStatement("select database()");
            setPtmtMap(ptmt);
            setRsMap(ptmt);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (ptmt != null) {
                try {
                    ptmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        setPrimaryClassMap();
    }

    public JdbcUtils() {
    }

    /**
     * 連線資料庫
     *
     * @return 若成功返回true,否則返回false
     */
    public boolean connect() {
        try {
            conn = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn != null;
    }

    /**
     * 按封裝好的POJO物件查詢條件,執行查詢操作
     *
     * @param obj 封裝好的查詢條件
     * @return 查詢後的ArrayList結果集
     */
    public List<T> ptmtQuery(T obj) {
        sql = "select * from ";
        String classSimpleName = obj.getClass().getSimpleName();
        sql += toStdName(classSimpleName);
        if (!addCondition(obj) || !setQuestionMarkContent(1, obj)) {
            return null;
        }
        try {
//            System.out.println(sql);
            rs = ptmt.executeQuery();
//            rs = ptmt.executeQuery("select * from student where 1=1 and id=1 and age=18");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return toArrayList();
    }

    /**
     * @param index 所設定問號開始的下標
     * @param obj   問號設定的內容,要封裝成POJO物件
     * @return 若設定成功返回true,否則返回false
     */
    public boolean setQuestionMarkContent(int index, T obj) {
        try {
            ptmt = conn.prepareStatement(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object fieldValue = field.get(obj);
                if (fieldValue == null)
                    continue;
                Class<?> fieldClass = field.getType();
                if (primaryClassMap.get(fieldClass) != null) {
                    fieldClass = primaryClassMap.get(fieldClass);
                }
                Method method = ptmtMap.get(fieldClass);
                method.invoke(ptmt, index++, fieldValue);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    /**
     * 給當前sql語句新增查詢或者刪除、修改的條件。即“where XXX”
     *
     * @param obj 條件封裝成的POJO物件
     * @return 若設定成功返回true,否則返回false
     */
    public boolean addCondition(T obj) {
        Class tClass = obj.getClass();
        Field[] declaredFields = tClass.getDeclaredFields();
        sql += " where 1=1";
        for (Field field : declaredFields) {
            String key = toStdName(field.getName());
            field.setAccessible(true);
            try {
                if (field.get(obj) != null) {
                    sql += " and " + key + "=?";
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    /**
     * 將資料庫中的表名、欄位名等轉換為規定的名字
     *
     * @param name 表名(即關係名)
     * @return 修改後的名字
     */
    public String toStdName(String name) {
        char[] nameChars = name.toCharArray();
        char[] s = new char[name.length() * 2];
        int len = 0;
        if (nameChars.length > 0) {
            if ((nameChars[0] & 0x20) != 0) //通過ASCII碼規律,判斷是否為大小寫
                s[len++] = nameChars[0];
            else
                s[len++] = (char) (nameChars[0] + 32);//轉換為小寫
        }
        for (int i = 1; i < nameChars.length; i++) {
            char c = nameChars[i];
            if ((c & 0x20) != 0) {  //通過ASCII碼規律,判斷是否為大小寫
                s[len++] = c;
            } else {
                s[len++] = '_';
                s[len++] = (char) (c + 32);//轉換為小寫
            }
        }
        s[len] = '\0';
        return String.valueOf(s,0,len);
    }

    /**
     * 將結果集轉換為ArrayList<T>物件
     *
     * @return 若成功,則返回結果集轉換的ArrayList<T>物件;否則返回null
     */
    public List<T> toArrayList() {
        if (rs == null)
            return null;
        List<T> list = new ArrayList<>();
        //獲取泛型的Class物件
        Class<T> tClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        Constructor<T> constructor = null;
        Field[] fields = tClass.getDeclaredFields();
        try {
            constructor = tClass.getConstructor();
            while (rs.next()) {
                T obj = constructor.newInstance();
                for (Field field : fields) {
                    field.setAccessible(true);
                    Method method = rsMap.get(field.getType());
                    Object value = method.invoke(rs, toStdName(field.getName()));
                    field.set(obj, value);
                }
                list.add(obj);
            }
        } catch (SQLException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
            return null;
        }
        return list;
    }
}