Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform batch update in Spring with a list of maps?

New to Spring, I am trying to insert a List<Map<String, Object>> into a table. Until now I have been using the SqlParameterSource for batch update, which works fine when a java bean is supplied to them. Something like this:

    @Autowired
    private NamedParameterJDBCTemplate v2_template;

    public int[] bulkInsertIntoSiteTable(List<SiteBean> list){
            SqlParameterSource[] batch = SqlParameterSourceUtils
                    .createBatch(list.toArray());
            int[] updateCounts = v2_template
                    .batchUpdate(
                            "insert into sitestatus (website, status, createdby) values (:website, :status, :username)",
                            batch);

            return updateCounts;

        }

However, I tried the same technique with a list of maps in place of a bean, it failed (rightly so).

public int[] bulkInsertIntoSiteTable(List<Map<String, Object>> list){
        SqlParameterSource[] batch = SqlParameterSourceUtils
                .createBatch(list.toArray());
        int[] updateCounts = v2_template
                .batchUpdate(
                        "insert into sitestatus (website, status, createdby) values (:website, :status, :username)",
                        batch);

        return updateCounts;

    }

The above code failed with the following exception:

Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter 'website': Invalid property 'website' of bean class [org.springframework.util.LinkedCaseInsensitiveMap]: Bean property 'website' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
    at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:322)
    at org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils$1.setValues(NamedParameterBatchUpdateUtils.java:45)
    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:893)
    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:1)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:587)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:615)
    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:884)
    at org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils.executeBatchUpdateWithNamedParameters(NamedParameterBatchUpdateUtils.java:40)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.batchUpdate(NamedParameterJdbcTemplate.java:303)
    at tester.utitlies.dao.VersionTwoDao.bulkInsertIntoSites(VersionTwoDao.java:21)
    at tester.utitlies.runner.Main.main(Main.java:28)

It fails as it considers the list to be a batch of beans, I guess. I cannot find a way to perform a batch update in Spring with a list of maps and using NamedParameterJDBCTemplate. Please advice.

like image 532
Mono Jamoon Avatar asked Jul 02 '13 10:07

Mono Jamoon


2 Answers

As per Spring NamedParameterJDBCTemplate docs, found here, this method can be used for batch updating with maps.

int[] batchUpdate(String sql, Map<String,?>[] batchValues)

The real challange was to a get an array of Map<String, Object> from a corresponding List<Map<String, Object>>. I used the following code to get the array and perform the batch update.

public static Map<String, Object>[] getArrayData(List<Map<String, Object>> list){
        @SuppressWarnings("unchecked")
        Map<String, Object>[] maps = new HashMap[list.size()];

        Iterator<Map<String, Object>> iterator = list.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            Map<java.lang.String, java.lang.Object> map = (Map<java.lang.String, java.lang.Object>) iterator
                    .next();
            maps[i++] = map;
        }

        return maps;
    }
like image 59
Mono Jamoon Avatar answered Oct 28 '22 23:10

Mono Jamoon


You can not directly use your bean in NamedParameterJdbcTemplate's batchUpdate, NamedParameterJdbcTemplate's batchUpdate accepts params in form of array only. Either an array of SqlParameterSource or an array of Map.

Here I will demonstrate how you can use array of Map to achieve your goal.

Considering the above problem, convert your List of Bean into array of map, Each map corresponds to one row to be inserted or One Bean object, field and its value are stored as key-value pair inside the map where key is the field name and value is the value of the field under consideration.

@Autowired
private NamedParameterJDBCTemplate v2_template;

public int[] bulkInsertIntoSiteTable(List<SiteBean> list){
        String yourQuery = "insert into sitestatus (website, status, createdby) 
               values (:website, :status, :username)"
        
        Map<String,Object>[] batchOfInputs = new HashMap[list.size()];
        int count = 0;
        for(SiteBean sb : list.size()){
           Map<String,Object> map = new HashMap();
           map.put("website",sb.getWebsite());
           map.put("status",sb.getStatus());
           map.put("username",sb.getUsername());
           batchOfInputs[count++]= map;
        }
        int[] updateCounts = v2_template.batchUpdate(yourQuery,batchOfInputs);

        return updateCounts;

    }
like image 36
Ashique Nawaz Avatar answered Oct 28 '22 22:10

Ashique Nawaz