【问题标题】:How to perform batch update in Spring with a list of maps?如何在 Spring 中使用地图列表执行批量更新?
【发布时间】:2013-06-29 15:34:05
【问题描述】:

Spring 新手,我正在尝试将 List<Map<String, Object>> 插入表中。到目前为止,我一直在使用SqlParameterSource 进行批量更新,当向它们提供 java bean 时它工作正常。像这样的:

    @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;

        }

但是,我尝试了使用映射列表代替 bean 的相同技术,但失败了(确实如此)。

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;

    }

以上代码失败,异常如下:

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)

它失败了,因为它认为列表是一批 bean,我猜。我找不到在 Spring 中使用 地图列表NamedParameterJDBCTemplate 执行批量更新的方法。请指教。

【问题讨论】:

    标签: java spring named-parameters batch-insert


    【解决方案1】:

    根据 Spring NamedParameterJDBCTemplate 文档,找到 here,此方法可用于使用地图进行批量更新。

    int[] batchUpdate(String sql, Map&lt;String,?&gt;[] batchValues)

    真正的挑战是从对应的List&lt;Map&lt;String, Object&gt;&gt; 中获取Map&lt;String, Object&gt; 的数组。我使用以下代码获取数组并执行批量更新。

    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;
        }
    

    【讨论】:

    • 为什么他们有 Map&lt;String,?&gt;[] batchValues 而没有 Map[] batchValues?
    • 以这种方式成功:Map[] batchValues = list.toArray(new HashMap[0]); namedParameterJdbcTemplate.batchUpdate("...", batchValues);
    • @Corin Fletcher - 你能粘贴你的代码吗?
    【解决方案2】:

    你不能直接在 NamedParameterJdbcTemplate 的 batchUpdate 中使用你的 bean,NamedParameterJdbcTemplate 的 batchUpdate 只接受数组形式的参数。 SqlParameterSource 数组或 Map 数组。

    在这里,我将演示如何使用 Map 数组来实现您的目标。

    考虑到上述问题,将您的 Bean 列表转换为地图数组, 每个映射对应于要插入的一行或 One Bean 对象,字段及其值作为键值对存储在映射内部,其中 key 是字段名称,value 是所考虑的字段的值。

    @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;
    
        }
    

    【讨论】:

      【解决方案3】:

      还有另一种方法可以避免@SuppressWarnings("unchecked")

      public static final String INSERT_INTO = "INSERT INTO {0} ({1}) VALUES ({2})";
      
      private NamedParameterJdbcTemplate template;
      
      
      template.batchUpdate(insertQuery(rowMaps.get(0)), batchArgs(mapRows));
      
      /**
       * Create SQL instruction INSERT from Map record
       *
       * @return literal INSERT INTO [schema].[prefix][table_name] (column1, column2, column3, ...)
       * VALUES (value1, value2, value3, ...);
       */
      public String insertQuery(Map<String, String> rowMap) {
          String schemaTable = Objects.isNull(getSchema()) ? table : getSchema() + "." + table;
          String splittedColumns = String.join(",", rowMap.keySet());
          String splittedValues = rowMap.keySet().stream()
                  .map(s -> ":" + s).collect(Collectors.joining(","));
          return MessageFormat.format(INSERT_INTO, schemaTable, splittedColumns, splittedValues);
      }
      
      private MapSqlParameterSource[] batchArgs(List<Map<String, String>> mapRows) {
          int size = mapRows.size();
          MapSqlParameterSource[] batchArgs = new MapSqlParameterSource[size];
          IntStream.range(0, size).forEach(i -> {
              MapSqlParameterSource args = new MapSqlParameterSource(mapRows.get(i));
              batchArgs[i] = args;
          });
      
          return batchArgs;
      }
      

      最好的问候

      【讨论】:

        【解决方案4】:

        一个工作的 sn-p :

         public List builkInsert(String insert,List details) {
        
                Map<String, Object>[] maps = new HashMap[details.size()];
                
                Map<String, Object>[] batchValues = (Map<String, Object>[]) details.toArray(maps);
                
                int[] response= namedParameterJdbcTemplate.batchUpdate(insert, batchValues);
            
                return Arrays.asList(response);
            }
        

        【讨论】:

          【解决方案5】:

          我用代码测试过。

          Map<String, Object>[] rs = new Map<String, Object>[1];
          
          Map<String, Object> item1 = new HashMap<>();
          item1.put("name", "Tien Nguyen");
          item1.put("age", 35);
          rs[0] = item1;
          
          NamedParameterJdbcTemplate jdbc = new NamedParameterJdbcTemplate(datasource); 
          // datasource from JDBC.
          jdbc.batchUpdate("call sp(:name, :age)", rs);
          

          希望很容易知道。 谢谢

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-07-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多