2

我正在尝试修改一些 Java 现有代码(不是我做的),我发现查询没有使用 prepare 语句完成。因为我有很多代码,所以我试图尽可能少地修改它。所以而不是像这样的方法

public void executeInsertStmt(String strQuery, String param1, String param2) {

...
...
PreparedStatement preparedStatement = cnx.prepareStatement(stringRequest);
preparedStatement.setString(1, param1);
preparedStatement.setString(2, param2);
}

我想做类似的事情(我不确定这是最好的解决方案)。

public void executeInsertStmt(String strQuery, ArrayList<ArrayList<Object>> parameters) {

PreparedStatement preparedStatement = cnx.prepareStatement(stringRequest);

int counter=1;
            for (final ArrayList<Object> eachParam : parameters) {

                switch(DataTypes.valueOf(eachParam.get(0).toString().toUpperCase()))
                {
                    case STRING:
                        preparedStatement.setString(counter, (String)eachParam.get(1));
                    break;
                    case DATE:
                        preparedStatement.setDate(counter, (Date)eachParam.get(1));
                    break;
                    case INT:
                        preparedStatement.setInt(counter, (Integer)eachParam.get(1));
                    break;
                    default:
                        preparedStatement.setString(counter, (String)eachParam.get(1));
                    break;
                }

                counter++;

            }
}

然后有这样的东西:

strQuery = "insert into toto values (?,?)";
ArrayList<Object> paramToPass1 = new ArrayList<Object>();

paramToPass1.add("String");
paramToPass1.add("TheValueForTheString");

ArrayList<Object> paramToPass2 = new ArrayList<Object>();

paramToPass2.add("String");
paramToPass2.add("TheValueForTheString2");

ArrayList<ArrayList<Object>> paramToPass = new ArrayList<ArrayList<Object>>();

paramToPass.add(paramToPass1);
paramToPass.add(paramToPass2);


executeInsertStmt(strQuery,paramToPass);

因为我有许多具有不同数量参数的查询,这种方法对我来说是最好的。我不必为每种类型的查询做一个方法。

你觉得怎么样。

有什么不对吗?是最好的方法吗?

感谢您的任何想法。

4

2 回答 2

1

您应该为参数使用对象表示,而不是 ArrayList<Object>大小为 2。此外,您不需要自己的DataType枚举,已经有一个java.sql.Types类。最重要的是,有一个setObject()方法PreparedStatement可以识别这些类型的值,因此您不需要switch声明或调用特定于类型的PreparedStatement.set..()方法。

这是一个解决方案,它具有参数的对象表示,利用java.sql.TypespreparedStatement.setObject()支持这些类型,并且还将您与类型常量值隔离开来。

首先,参数的对象表示:

import java.sql.Types;

public class ParamDescriptor {
    // Constructor itself is private, we are encapsulating so that
    // you don't need to write java.sql.Types constants yourself
    private ParamDescriptor(int dataType, Object value) {
        _dataType = dataType;
        _value = value;
    }

    // Factory methods for actual instantiation
    public static ParamDescriptor forInt (int paramVal) {
        return new ParamDescriptor (Types.INTEGER, paramVal);
    }

    public static ParamDescriptor forString (String paramVal) {
        return new ParamDescriptor (Types.VARCHAR, paramVal);
    }

    public static ParamDescriptor forDate (Date paramVal) {
        return new ParamDescriptor (Types.DATE, paramVal);
    }
    // Add more here to support more data types . . . .    


    public int getDataType() {
        return _dataType;
    }

    public Object getValue() {
        return _value;
    }

    private int     _dataType;
    private Object  _value;
}

接下来,新版本的executeInsertStmt(). 我们已将其缩减为仅几行代码,并且无论将来是否支持参数类型,它都无需再次更改:

  public void executeInsertStmt(String strQuery, List<ParamDescriptor> parameters) throws SQLException {    
        PreparedStatement preparedStatement = cnx.prepareStatement(strQuery);

        int counter = 1;
        for (ParamDescriptor paramDescriptor : parameters) {
            preparedStatement.setObject(counter, 
                                        paramDescriptor.getValue(),
                                        paramDescriptor.getDataType());
            counter++;
        }
    }

最后,调用 new 的代码executeInsertStmt()

String strQuery = "insert into toto values (?,?)";

ParamDescriptor paramToPass1 = ParamDescriptor.forString("TheValueForTheString");
ParamDescriptor paramToPass2 = ParamDescriptor.forString("TheValueForTheString2");

List<ParamDescriptor> parameters = new ArrayList<ParamDescriptor>();
parameters.add(paramToPass1);
parameters.add(paramToPass2);

executeInsertStmt(strQuery, parameters);

请注意,如果您计划处理小数,还有另一个版本PreparedStatement.setObject()支持指定小数刻度。您可能需要在executeInsertStmt().

于 2012-04-12T14:48:00.630 回答
0

好吧,您的想法还不错……只是一些指示。

不要传递 ArrayList 的 ArrayList... 而是使用 instanceof 或 DataHolder 类。

方法一:instanceof

简单添加类型 Integer、String、Double 等,然后在您的方法中:

public void executeInsertStmt(String strQuery, ArrayList<Object> parameters) {

    PreparedStatement preparedStatement = cnx.prepareStatement(stringRequest);
    int counter=1;
    for (final Object eachParam : parameters) {
        if (eachParam instanceof String) {
            preparedStatement.setString(counter, (String)eachParam); 
        } else if (eachParam instanceof Integer) {
            preparedStatement.setInt(counter, (Integer)eachParam); 
        } else ...

        counter++;

    }
}

DataHolder 的想法是一个字段将保留类型,另一个字段将保留实际数据。您甚至可以使用泛型使其更好。但是,在这种情况下,我会选择 instanceof 。

于 2012-04-12T14:18:25.213 回答