實現通用的PreparedStatement更新記錄的方法

        在JadePool中,除了常規的更新方法之外,還有以下更新記錄的方法,

           1、public int update(String tableName, Map<String, Object> mapRecord, String where) throws SQLException//根據條件更新單條記錄
           2、public int update(String tableName, Map<String, Object> mapRecord) throws SQLException//更新單條記錄
           3、public int update(String tableName, List<Map> listRecord) throws SQLException  //更新多條記錄,主鍵值不變
           4、public int update(String tableName, List<Map> listRecord, String where) throws SQLException   //根據where條件,更新多條記錄,主鍵值不變

        它們都調用底層最核心的方法
            private int _preparedStatementUpdate(String tableName, List<Map> listRecord, boolean isUpdateKey, String whereStr) throws SQLException

        將使用參數Map變量或者是List<Map>變量更新數據庫表中的記錄,待更新的記錄的條件是主鍵值等於mapRecord.get(主鍵名),在這一組操作中,主鍵值不變。

        底層核心方法_preparedStatementUpdate同__preparedStatementInsert的共同點有以下幾點:
           1、插入語句或更新語句只需要合成一次;
           2、都支持相同的SQL數據類型及其對應的Java類;
           3、都需要實現相同的通配符對應的賦值方法(參見“SQL數據類型與Java類的對應關係”一文);
           4、都整合相同的異常,統一拋出SQLException異常。

        底層核心方法_preparedStatementUpdate同__preparedStatementInsert的區別在於:
           1、合成PreparedStatement的更新語句;
           2、更新數據時,保持主鍵值不變。

        合成PreparedStatement的更新語句的算法是

        Map<String, Object> _m = new LinkedHashMap(listRecord.get(0));//獲取一條記錄,作爲過濾、分組依據
        String[] tableFields = db.getFields(tableName);//表中的字段
        String[] tableKeys = db.getKeys(tableName);//表中的主鍵
        Object[] recordFields = (_m.keySet()).toArray(); //獲取記錄裏的字段名的集合
        for (int i = 0; i < recordFields.length; i++) {
            if (!tool.isInFields(tableFields, recordFields[i].toString())) {
                _m.remove(recordFields[i].toString());//移除無效字段, 查看記錄中的字段在表中是否存在,如果不存在,則移除到
            }
        }
        Object[] k0 = (_m.keySet()).toArray(); //過濾後的有效字段
        Map<String, Object> key_m = new LinkedHashMap();//記錄裏的主鍵
        if (!isUpdateKey) {
            for (int i = 0; i < k0.length; i++) {
                if (tool.isInFields(tableKeys, k0[i].toString())) {//記錄中是否有主鍵
                    key_m.put(k0[i].toString(), _m.remove(k0[i].toString()));//將記錄中的主鍵移到key_m中;保證不對主鍵更新
                }
            }
        }
        Object[] fields = (_m.keySet()).toArray(); //記錄中不包含主鍵的有效字段;再次過濾掉主鍵字段的結果
        Object[] keys = (key_m.keySet()).toArray(); //記錄中包含的主鍵


        if (isUpdateKey) {
            if (keys.length == 0 || keys.length != tableKeys.length) {
                return num;
            }
        }


        String[] kss = new String[fields.length]; //保存"鍵名=?"
        for (int i = 0; i < fields.length; i++) {
            kss[i] = fields[i].toString() + "=?";
        }

        String n_v = tool.arryToString(kss, ",");

        String preparedStatementUpdate = "update " + tableName + " set " + n_v + " ";
        //System.out.println(preparedStatementUpdate);


        完整的_preparedStatementUpdate代碼

    /**
     * 使用PreparedStatement更新多條記錄 本方法是根據JDBC API類名的判斷來存貯數據<br/>
     * 爲了方便表單數據的錄入,本方法提供了用字符串來表達Integer|Long|Short|Float|Double|Bigdecimal|java.sql.Date等常規類型的支持,<br/>
     * 但請注意:用字符串表達Date時,目前java.sql.Date僅支持將"yyyy-mm-dd"格式轉換成Date對象;<br/>
     * 對於其它類型,用戶必須建立相應類型的對象; 本方法提供了對上傳文件的支持; 零長度字符串將保存爲null。<br/>
     * 詳細的數據類型,可參閱《Java開發者年鑑》p700 PreparedStatement的setXXX方法<br/>
     *
     *
     * 完成更新的步驟: 1、過濾記錄中無效字段,得有效字段Object[] fields<br/>
     * 2、根據isUpdateKey對有效字段繼續分組:!true時,再得主鍵字段組Object[] keys和非主鍵字段組Object[]
     * fields<br/> 3、自動生成PreparedStatement所需的更新操作<br/> 4、迭代記錄for (Map record :
     * listRecord) {}<br/> 5、執行PreparedStatement的executeUpdate(updateSQL);<br/>
     *
     *
     * @param tableName 是一個表名
     * @param listRecord 是具有相同結構的一組記錄
     * @param isUpdateKey 是否更新主鍵
     * @param whereStr
     * 是操作條件,插入時不起作用,更新時,若where==null||"".equals(where),則自動根據記錄自身主鍵字段的鍵值對組合where條件語句
     * 是從LinkedHashMap參數中獲取的值
     * @throws SQLException
     */
    private int _preparedStatementUpdate(String tableName, List<Map> listRecord, boolean isUpdateKey, String whereStr) throws SQLException {
        int num = 0;
        if (listRecord == null || listRecord.isEmpty()) {
            return num;
        }
        Map<String, Object> _m = new LinkedHashMap(listRecord.get(0));//獲取一條記錄,作爲過濾、分組依據
        String[] tableFields = db.getFields(tableName);//表中的字段
        String[] tableKeys = db.getKeys(tableName);//表中的主鍵
        Object[] recordFields = (_m.keySet()).toArray(); //獲取記錄裏的字段名的集合
        for (int i = 0; i < recordFields.length; i++) {
            if (!tool.isInFields(tableFields, recordFields[i].toString())) {
                _m.remove(recordFields[i].toString());//移除無效字段, 查看記錄中的字段在表中是否存在,如果不存在,則移除到
            }
        }
        Object[] k0 = (_m.keySet()).toArray(); //過濾後的有效字段
        Map<String, Object> key_m = new LinkedHashMap();//記錄裏的主鍵
        if (!isUpdateKey) {
            for (int i = 0; i < k0.length; i++) {
                if (tool.isInFields(tableKeys, k0[i].toString())) {//記錄中是否有主鍵
                    key_m.put(k0[i].toString(), _m.remove(k0[i].toString()));//將記錄中的主鍵移到key_m中;保證不對主鍵更新
                }
            }
        }
        Object[] fields = (_m.keySet()).toArray(); //記錄中不包含主鍵的有效字段;再次過濾掉主鍵字段的結果
        Object[] keys = (key_m.keySet()).toArray(); //記錄中包含的主鍵


        if (isUpdateKey) {
            if (keys.length == 0 || keys.length != tableKeys.length) {
                return num;
            }
        }


        String[] kss = new String[fields.length]; //保存"鍵名=?"
        for (int i = 0; i < fields.length; i++) {
            kss[i] = fields[i].toString() + "=?";
        }

        String n_v = tool.arryToString(kss, ",");

        String preparedStatementUpdate = "update " + tableName + " set " + n_v + " ";
        //System.out.println(preparedStatementUpdate);

        PreparedStatement pstmt = null;

        try {

            if (whereStr != null) {
                pstmt = con.prepareStatement(preparedStatementUpdate + whereStr);//如果whereStr!=null,從這裏執行PrepareStatement更新
            }

            for (Map record : listRecord) {

                if (whereStr == null) {
                    String _w = "";

                    if (keys.length > 0) {
                        Field f = db.getField(tableName, keys[0].toString());
                        Object _o = record.get(keys[0].toString());
                        String _s = "";
                        if (f.getTypeClassName().equals("java.lang.String")) {
                            _s = keys[0].toString() + " like '" + _o.toString() + "'";
                        } else {
                            _s = keys[0].toString() + " = " + _o.toString();
                        }
                        if (keys.length > 1) {
                            for (int i = 1; i < keys.length; i++) {
                                f = db.getField(tableName, keys[i].toString());
                                _o = record.get(keys[i].toString());
                                if (f.getTypeClassName().equals("java.lang.String")) {
                                    _s = _s + " and " + keys[i].toString() + " like '" + _o.toString() + "'";
                                } else {
                                    _s = _s + " and " + keys[i].toString() + " = " + _o.toString();
                                }
                            }
                        }
                        _w = " where " + _s;
                    }

                    //System.out.println(preparedStatementUpdate + _w);//批量更新
                    pstmt = con.prepareStatement(preparedStatementUpdate + _w);//如果whereStr==null,從這裏執行PrepareStatement更新//條件不同,只能逐條變更插入語句
                }


                //爲了提高運算效率,規定判斷條件優先順序:常用標準條件精確匹配、標準條件精確匹配、非標準條件精確匹配、非標準條件概略匹配、非標準條件概略小寫匹配

                for (int i = 0; i < fields.length; i++) {
                    Field f = db.getField(tableName, fields[i].toString());
                    String className = f.getTypeClassName();
                    int index = f.getSqlType();
                    Object v = record.get(fields[i].toString());

                    if (v == null) {
                        pstmt.setNull(i + 1, index);//continue;
                    } else if (v != null) {
                        String _c = ((Class) v.getClass()).getName(); //增加對錶單數據的支持,在表單中獲取的數據均爲String型,固應對其進行轉換.
                        if ((_c.equals("java.lang.String")) && ("".equals(((String) v).trim()))) {
                            pstmt.setNull(i + 1, index);//continue;
                        } else {
                            if (className.equals("java.lang.String")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setString(i + 1, (String) v);
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Integer")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setInt(i + 1, Integer.parseInt((String) v));
                                } else {
                                    if (_c.equals("java.lang.Integer")) {
                                        pstmt.setInt(i + 1, ((Integer) v).intValue());
                                    } else {
                                        Integer n = new Integer(v.toString());
                                        pstmt.setInt(i + 1, n);
                                    }
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Long")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setLong(i + 1, Long.parseLong((String) v));
                                } else {
                                    if (_c.equals("java.lang.Long")) {
                                        pstmt.setLong(i + 1, ((Long) v).longValue());
                                    } else {
                                        Long l = new Long(v.toString());
                                        pstmt.setLong(i + 1, l);
                                    }
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Short")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setShort(i + 1, Short.parseShort((String) v));
                                } else {
                                    pstmt.setShort(i + 1, ((Short) v).shortValue());
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Float")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setFloat(i + 1, Float.parseFloat((String) v));
                                } else {
                                    pstmt.setFloat(i + 1, ((Float) v).floatValue());
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Double")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setDouble(i + 1, Double.parseDouble((String) v));
                                } else {
                                    pstmt.setDouble(i + 1, ((Double) v).doubleValue());
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Boolean")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setBoolean(i + 1, (Boolean.valueOf((String) v)).booleanValue());
                                } else {
                                    pstmt.setBoolean(i + 1, ((Boolean) v).booleanValue());
                                }
                                continue;
                            }

                            if (className.equals("java.sql.Timestamp")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    String _s = ((String) v).trim();
                                    if (tool.matches(RegexType.chinaDate, _s)) {//如:2012-01-24
                                        Time t = new Time(0l);
                                        _s = _s + " " + t.toString();
                                        pstmt.setTimestamp(i + 1, java.sql.Timestamp.valueOf(_s));
                                    } else {
                                        pstmt.setTimestamp(i + 1, java.sql.Timestamp.valueOf((String) v));
                                    }
                                } else if (className.equals("java.sql.Date")) {
                                    java.sql.Date _v = (java.sql.Date) v;
                                    pstmt.setTimestamp(i + 1, new Timestamp(_v.getTime()));
                                } else if (className.equals("java.util.Date")) {
                                    java.util.Date _v = (java.util.Date) v;
                                    pstmt.setTimestamp(i + 1, new Timestamp(_v.getTime()));
                                } else if (className.equals("java.sql.Time")) {
                                    java.sql.Time _v = (java.sql.Time) v;
                                    pstmt.setTimestamp(i + 1, new Timestamp(_v.getTime()));
                                } else {
                                    pstmt.setTimestamp(i + 1, new Timestamp(((java.util.Date) v).getTime()));//能支持更多的應用
                                    //pstmt.setTimestamp(i + 1,  (java.sql.Timestamp) v);//使用jsf日期轉換後獲得的結果可能不完整,這時會出現轉換異常
                                }
                                continue;
                            }

                            if (className.equals("java.sql.Date") || className.equals("java.util.Date")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setDate(i + 1, java.sql.Date.valueOf((String) v));
                                } else if (className.equals("java.util.Date")) {
                                    java.util.Date _v = (java.util.Date) v;
                                    pstmt.setDate(i + 1, new java.sql.Date(_v.getTime()));
                                } else {
                                    pstmt.setDate(i + 1, (java.sql.Date) v);
                                }
                                continue;
                            }

                            if (className.equals("java.sql.Time")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setTime(i + 1, java.sql.Time.valueOf((String) v));
                                } else {
                                    pstmt.setTime(i + 1, (java.sql.Time) v);
                                }
                                continue;
                            }

                            if (className.equals("[B") || className.equals("byte[]")) {
                                //SQL Server 的image、timestamp、binary類型是byte[],MySQL 的blob系列是java.lang.Object,Sybase的image是[B
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setBytes(i + 1, ((String) v).getBytes());
                                } else {
                                    pstmt.setBytes(i + 1, (byte[]) v);
                                }
                                continue;
                            }
                            if (className.equals("java.sql.Blob")) {
                                //SQL Server 的image、timestamp、binary類型是byte[],MySQL 的blob系列是java.lang.Object,Sybase的image是[B
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setBytes(i + 1, ((String) v).getBytes());
                                } else {
                                    pstmt.setBlob(i + 1, (java.sql.Blob) v);
                                }
                                continue;
                            }
                            if (className.equals("java.lang.Object")) {
                                //SQL Server 的image、timestamp、binary類型是byte[],MySQL 的blob系列是java.lang.Object,Sybase的image是[B
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setBytes(i + 1, ((String) v).getBytes());
                                } else {
                                    pstmt.setObject(i + 1, v);
                                }
                                continue;
                            }

                            if (className.equals("java.lang.Byte")) {
                                //MySQL的tinyint是java.lang.Byte
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setByte(i + 1, java.lang.Byte.parseByte((String) v));
                                } else {
                                    pstmt.setByte(i + 1, java.lang.Byte.parseByte(v.toString()));
                                }
                                continue;
                            }

                            if (className.equals("java.math.BigDecimal")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setBigDecimal(i + 1, new BigDecimal((String) v));
                                } else {
                                    pstmt.setBigDecimal(i + 1, (BigDecimal) v);
                                }
                                continue;
                            }

                            //以下部分將根據具體的數據庫需要而定,有待驗證
                            if (className.equals("java.sql.Clob")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setString(i + 1, (String) v);//給clob類型的字段賦予字符串型
                                } else {
                                    pstmt.setClob(i + 1, (java.sql.Clob) v);
                                }
                                continue;
                            }


                            //以下部分將根據具體的數據庫需要而定,有待驗證
                            if (className.equals("java.sql.Array")) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    //
                                } else {
                                    pstmt.setArray(i + 1, (java.sql.Array) v);
                                }
                                continue;
                            }

                            //特殊類型,非常用,置後
                            if (className.equals("com.sybase.jdbc2.tds.SybTimestamp") || className.toLowerCase().indexOf("timestamp") > 0) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setTimestamp(i + 1, java.sql.Timestamp.valueOf((String) v));
                                } else {
                                    pstmt.setTimestamp(i + 1, (java.sql.Timestamp) v);
                                }
                                continue;
                            }

                            //概略匹配
                            if (className.toLowerCase().indexOf("date") > 0) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setDate(i + 1, java.sql.Date.valueOf((String) v));
                                } else {
                                    pstmt.setDate(i + 1, new java.sql.Date(((java.util.Date) v).getTime()));
                                }
                                continue;
                            }

                            if (className.toLowerCase().indexOf("time") > 0) {
                                if ((_c.equals("java.lang.String")) && (!"".equals(((String) v).trim()))) {
                                    pstmt.setTime(i + 1, java.sql.Time.valueOf((String) v));
                                } else {
                                    pstmt.setTime(i + 1, (java.sql.Time) v);
                                }
                                continue;
                            }

                            if (_c.equals("java.io.FileInputStream")) {
                                //調用如:FileInputStream in = new FileInputStream("D:\\test.jpg");的結果
                                pstmt.setBinaryStream(i + 1, (FileInputStream) v, ((FileInputStream) v).available());
                                continue;
                            }//java.io.FileInputStream
                            //其它特殊類型,非常用,置後,更多的setXXX方法詳見《年鑑》p700
                        }
                    }
                }
                num = num + pstmt.executeUpdate();
            }
        } catch (java.lang.ClassCastException ex) {
            throw new SQLException("java.lang.ClassCastException: " + ex.getMessage(), ex.getCause());
        } catch (NumberFormatException ex) {
            throw new SQLException("NumberFormatException: " + ex.getMessage(), ex.getCause());
        } catch (IOException ex) {
            throw new SQLException("IOException: " + ex.getMessage(), ex.getCause());
        } finally {
            pstmt.close();
        }

        return num;
    }


        通配符對應的賦值方法參見“SQL數據類型與Java類的對應關係”一文






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章