1

I have created a custom function to insert data in my MySQL database. The functions first creates a query based on the input given. The query wil look like INSERT INTO tableName (columnName1, ..., columnNamei) VALUES (?, ..., ?), ..., (?, ...,?). After that, the PreparedStatement needs to made, which contains the real values. These need to be added to a batch, because I want to add multiple rows at once (as showed here: Java: Insert multiple rows into MySQL with PreparedStatement). Here is the code:

insertData() Function

public static void insertData(String table, List<HashMap<String, Object>> list) throws SQLException {

    //Create query: make sure all of the rows in the table get the same amount of values passed
    //Prepare colnames string
    String colNamesParsed = "";
    int counter = 1;

    //Iterate over only the first hashmap of the list (THATS WHY ALL THE ROWS NEED TO HAVE THE SAME AMOUNT OF VALUES PASSED)
    for (String colName : list.get(0).keySet()) {

        //Check if it is the last col name
        if (counter != list.get(0).keySet().size()) {
            colNamesParsed = colNamesParsed + colName+", ";
        }
        else {
            colNamesParsed = colNamesParsed + colName;
        }

        counter++;
    }

    //Now create the place holder for the query variables
    String queryVariablesPlaceholder = "";
    int rowSize = 0;
    for (HashMap<String, Object> row : list) {

        //This part is to check if all row sizes are equal
        if (rowSize == 0) {
            rowSize = row.values().size();
        }
        else {
            //Check if the rowsize is equal for all rows
            if (row.values().size() != rowSize) {
                System.out.println("The rows of the arrays are from a different size");
                return;
            }
        }

        String queryVariablesRow = "(?, ";
        for (int j = 1; j < (row.values().size()-1); j++) {
            queryVariablesRow = queryVariablesRow+"?, ";
        }
        queryVariablesRow = queryVariablesRow+"?)";

        //Make sure the query does not start with a comma
        if (queryVariablesPlaceholder.equals("")) {
            queryVariablesPlaceholder = queryVariablesRow;
        }
        else {
            queryVariablesPlaceholder = queryVariablesPlaceholder+", "+queryVariablesRow;
        }
    }

    //The MySQL query needs to be built now
    String query = "INSERT INTO "+table+" ("+colNamesParsed+") VALUES "+queryVariablesPlaceholder+";";
    System.out.println(query);

    //Init prepared statement
    PreparedStatement statement = con.prepareStatement(query);

    for (HashMap<String, Object> map : list) {

        int varCounter = 1;
        //Iterate over all values that need to be inserted
        for (Object object : map.values()) {

            if (object instanceof Integer) {
                statement.setInt(varCounter, Integer.parseInt(object.toString()));
            }
            else if (object instanceof String) {
                statement.setString(varCounter, object.toString());
            }
            else if (object instanceof Timestamp) {
                statement.setTimestamp(varCounter, parseStringToTimestamp(object.toString()));
            }
            else if (object instanceof Double) {
                statement.setDouble(varCounter, Double.parseDouble(object.toString()));
            }
            System.out.println(varCounter);
            varCounter++;
        }

        //Add row to the batch
        try {
            statement.addBatch();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

    }
    //Execute the query, which is in fact the batch
    statement.executeBatch();
}

When I want to insert some data in the database, I execute the following code:

Functional part

List<HashMap<String, Object>> list = new ArrayList<>();
    for (Object object : listOfObjects) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("columnName1", object.getSomeValue());
        /....../
        map.put("columnName2", object.getSomeOtherValue());

        list.add(map);
    }

    Functions.insertData("tableName", list);

Creating the dynamic query seems to work perfectly. However, I can't get the statement.addBatch() to work. It keeps giving me the following error:

java.sql.SQLException: No value specified for parameter 9

I don't get it, because I only have 8 parameters to pass in every unit of the batch. My target table has 9 columns, so I tried to add a value for that column, but then it says: No value specified for parameter 10, so it seems like it isn't closing the 'batch unit' or something.

What am I missing here?

Any help is greatly appreciated!

2
  • You might want to read on batch statements (see this question for example) Commented Nov 14, 2014 at 12:26
  • Thanks for your comment @RC. If I add statement.clearParameters(), I get this error: java.sql.SQLException: No value specified for parameter 1. So does not change the situation. Furthermore, I think my code is the same as mentioned in your example. Commented Nov 14, 2014 at 12:42

1 Answer 1

1

This

INSERT INTO tableName (columnName1, ..., columnNamei) VALUES (?, ..., ?), ..., (?, ...,?) 

is not standard SQL syntax. If you use this JDBC will a parameter for each "?" in your query.

Use:

INSERT INTO tableName (columnName1, ..., columnNamei) VALUES (?, ..., ?)

and add every statement to a batch.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your answer! In this example (stackoverflow.com/questions/4355046/…) there is stated that I am using a standard SQL syntax.
I figured it out with this: I had based my code on this example: electrictoolbox.com/mysql-insert-multiple-records, from which I concluded that I would need multiple (?,?,?....?). For the batch functionality, only one is sufficient. Can anyone tell me why this is the case?
When you use batch update + PreparedStatement, what happens is: 1. The SQL is compiled only one, and not on every execution. This is 1 time saver; 2. All the inserts are send to the database and executed in bulk, which means it does not use the cycle send statement + execute it + return the result/errors to the client. This is another time saver. It is basically the equivalent for the INSERT with multiple (?, ..?), even in performance.
Very well explained! I totally get it now and I understand that I mixed up two different techniques.
Maybe it could be useful to emphasize this difference in your answer as well, to be able to help other people that struggle with this too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.