使用 QueryRunner 插入 ArrayList<Object[]>

Posted

技术标签:

【中文标题】使用 QueryRunner 插入 ArrayList<Object[]>【英文标题】:Using QueryRunner to insert ArrayList<Object[]> 【发布时间】:2011-10-13 09:45:27 【问题描述】:

我想使用QueryRunner 来插入一个ArrayList。我在网上找到的唯一信息是插入一个 Object[]。大致如下:

qr.update("insert into MyTable (param1,param2,param3) values (?,?,?)",
new Object[]  str1, str2, str3);

我显然希望避免遍历整个 ArrayList 并一次插入一个索引,因为每次插入的行数都是未知的。

我只是想看看有没有人这样做过。查询返回一个列表,所以我不明白为什么我不能插入一个列表。任何建议表示赞赏。谢谢。

【问题讨论】:

【参考方案1】:

我也在为此苦苦挣扎,但决定创建一个modelToSqlConverter。这不是我写过的最漂亮的代码,但它就像一个魅力。

我实际上已经围绕 Dbutils 创建了一个小包装器,我称之为 GenericDataAccessor。这是一项正在进行的工作,我一有时间就会把它放在 github 上。对于所有中型项目来说,它是一个很棒的工具,对于像 Hibernate 这样的真正 ORM 来说感觉很小,但对于仅使用 JDBC 来说就很大。无论如何。如果您愿意,请随时使用它,它对我有很大帮助。

这里是模型转换器

    /**
 * The <code>ModelToSqlConverter</code> class <br>
 * <br>
 * Deserializes the model and creates the sql string for update and insert.<br>
 * Also generates the object array for the values from the model.
 */
public class ModelToSqlConverter

    private Object model;

    private List<Object> params, keyParams, modelList;

    private String fieldNameString, questionMarkString, sqlString, conditionString, updateString;

    private boolean update;

    private String[] keys;

    private Object[][] multiParams;

    /**
     * Initializes a newly created <code>ModelToSqlConverter</code>
     *
     * @param model The model representing the ASW file.
     * @param keys The keys for locating the right row in ASW file.
     */
    @SuppressWarnings("unchecked")
    private ModelToSqlConverter(Object model, String... keys)
        this.model = model;
        this.keys = keys;
        params = new ArrayList<>();
        keyParams = new ArrayList<>();
        questionMarkString = "VALUES (";
        fieldNameString = "(";
        updateString = "";
        conditionString = "WHERE ";
        update = keys != null && keys.length > 0;
        if(model instanceof List<?>)
            modelList = (List<Object>) model;
            convertModelListToSqlAndParams();
        else
            convertModelToSqlAndParams();
        

    

    /**
     * Main method for Converting Model into SQL String and to value parameters.
     */
    private void convertModelToSqlAndParams()

        for(Field field : model.getClass().getDeclaredFields())
            try
                field.setAccessible(true);
                Object value = field.get(model);
                String fieldName = field.getName();
                if(value != null && !fieldName.equalsIgnoreCase("serialVersionUID"))
                    if(!update)
                        addQuestionMark();
                        addNameToSql(fieldName);
                        addValueToObjectArray(value);
                    else
                        if(isKey(fieldName))
                            conditionString += fieldName + " = ?,";
                            keyParams.add(value);

                        else
                            addParamAndNameToSql(fieldName);
                            addValueToObjectArray(value);
                        
                    
                

            catch(IllegalArgumentException e)
                // TODO Auto-generated catch block
                e.printStackTrace();
            catch(IllegalAccessException e)
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
        sqlString = update ? getUpdateSql() : getInsertSql();
        for(Object key : keyParams)
            addValueToObjectArray(key);
        
    

    /**
     * Main method for Converting Model into SQL String and to value parameters.
     */
    private void convertModelListToSqlAndParams()
        int row = 0;
        boolean isKey = false;
        boolean firstModel = true;
        Field[] fields = modelList.get(0).getClass().getDeclaredFields();
        multiParams = new Object[modelList.size()][fields.length];
        for(Object model : modelList)
            int col = 0;
            keyParams = new ArrayList<>();
            for(Field field : fields)
                try
                    field.setAccessible(true);
                    Object value = field.get(model);
                    String fieldName = field.getName();
                    if(value != null && !fieldName.equalsIgnoreCase("serialVersionUID"))
                        if(!update)
                            if(firstModel)
                                addQuestionMark();
                                addNameToSql(fieldName);
                            
                            addValueToMultiParams(value, row, col);
                        else
                            isKey = isKey(fieldName);
                            if(isKey)
                                if(firstModel)
                                    conditionString += fieldName + " = ?,";
                                
                                keyParams.add(value);
                            else
                                if(firstModel)
                                    addParamAndNameToSql(fieldName);
                                addValueToMultiParams(value, row, col);
                            
                        
                    

                catch(IllegalArgumentException e)
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                catch(IllegalAccessException e)
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                

                if(!isKey)
                    col++;
            
            firstModel = false;
            for(Object key : keyParams)
                addValueToMultiParams(key, row, col);
                col++;
            
            row++;
        
        sqlString = update ? getUpdateSql() : getInsertSql();

    

    /**
     * @param columnName
     */
    private void addNameToSql(String columnName)
        fieldNameString += columnName + ",";
    

    /**
     * @param value
     */
    private void addValueToObjectArray(Object value)
        params.add(value);
    

    /**
     * @param value
     * @param row
     * @param col
     */
    private void addValueToMultiParams(Object value, int row, int col)
        multiParams[row][col] = value;
    

    public Object[][] getMultiValueParams()
        return removeNullsFromMultiArray(multiParams);
    

    /**
     * Adds question mark to string
     */
    private void addQuestionMark()
        questionMarkString += "?,";
    

    /**
     * @param columnName
     */
    private void addParamAndNameToSql(String columnName)
        updateString += columnName + "= ?,";
    

    /**
     * @return the update SQL string.
     */
    private String getUpdateSql()
        return updateString.substring(0, updateString.lastIndexOf(",")) + " " + conditionString.substring(0, conditionString.lastIndexOf(","));
    

    /**
     * @return the insert SQL string.
     */
    private String getInsertSql()
        return fieldNameString.substring(0, fieldNameString.lastIndexOf(",")) + ") " + questionMarkString.substring(0, questionMarkString.lastIndexOf(","))
                + ")";
    

    private Object[][] removeNullsFromMultiArray(Object[][] multiValuedArray)
        for(int i = 0; i < multiValuedArray.length; i++)
            ArrayList<Object> list = new ArrayList<Object>(); // creates a list to store the elements !=
                                                                // null
            for(int j = 0; j < multiValuedArray[i].length; j++)
                if(multiValuedArray[i][j] != null)
                    list.add(multiValuedArray[i][j]); // elements != null will be added to the list.
                
            
            multiValuedArray[i] = list.toArray(new Object[list.size()]); // all elements from list to an
                                                                            // array.
        
        return multiValuedArray;
    

    /**
     * Checks if the field name is a key.
     * 
     * @param fieldName
     * @return true if the field is a key.
     */
    private boolean isKey(String fieldName)
        boolean isKey = false;
        for(String key : keys)
            if(fieldName.equalsIgnoreCase(key))
                isKey = true;
            
        
        return isKey;
    

    /**
     * @return the params
     */
    public Object[] getParams()
        return params.toArray();
    

    /**
     * @return the sqlString
     */
    public String getSqlString()
        return sqlString;
    

    /**
     * @param params the params to set
     */
    public void setParams(List<Object> params)
        this.params = params;
    

    /**
     * @param sqlString the sqlString to set
     */
    public void setSqlString(String sqlString)
        this.sqlString = sqlString;
    


这是您调用插入的方法。

/**
 * Insert batch of rows from model list into the Database.
 * 
 * @param modelsList List of model objects representing the Database table.
 * @return int Array of inserted rows.
 * @throws SQLException
 */
public <T> int[] insertWithListOfModels(List<T> modelsList) throws SQLException
    ModelToSqlConverter modelConverter = new ModelToSqlConverter(modelsList);
    QueryRunner qryRunner = new QueryRunner();
    int[] inserts = null;
    System.out.println("INSERT INTO " + modelsList.get(0).getClass().getSimpleName().toUpperCase() + " " + modelConverter.getSqlString());
    System.out.println(Arrays.deepToString(modelConverter.getMultiValueParams()));
    inserts = qryRunner.batch(connection,
            "INSERT INTO " + modelsList.get(0).getClass().getSimpleName().toUpperCase() + " " + modelConverter.getSqlString(),
            modelConverter.getMultiValueParams());
    return inserts;

它的工作方式是,您提交模型列表或仅提交单个对象。我提供的方法是使用模型列表进行更新,但你明白了。 modelToSqlConvertor 的构造函数处理一切。然后,使用 dbutils qryRunner 声明 sql 并从 modelToSqlConverter 调用 getter 获取值和参数。

要使这个工作你的模型必须与你的数据库表相同。我用 JPA 创建了我的模型。

希望这会有所帮助!

【讨论】:

【参考方案2】:

我知道这是旧的,但我正在寻找有关 Apache Commons DBUtils QueryRunner 的信息并遇到了这个......为了将来参考,您可以:

先将ArrayList转成Object[][]:

Object[][] params = null;
params = listOfObjectArrays.toArray(params);

然后将params 传递给QueryRunner 上的批处理方法(返回int[]):

qr.batch("insert into MyTable (param1,param2,param3) values (?,?,?)", params);

【讨论】:

我也在为此苦苦挣扎。我有 List 个人 = new ArrayList();如果我尝试你的方法,我会遇到铸造问题。我该如何解决这个问题?对象[][] 参数 = null; params = people.toArray(params);

以上是关于使用 QueryRunner 插入 ArrayList<Object[]>的主要内容,如果未能解决你的问题,请参考以下文章

c3p0和QueryRunner的结合使用,让开发更加简便

DBUtils框架的使用(下)

QueryRunner的使用

QueryRunner的使用

DBUtils QueryRunner 实例化

QueryRunner类