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のバッチであると見なされるため、失敗します。 マップのリストでNamedParameterJDBCTemplate
を使用して、Springでバッチ更新を実行する方法が見つかりません。アドバイスをお願いします。
Spring NamedParameterJDBCTemplate
docs、found here によると、このメソッドはマップを使用したバッチ更新に使用できます。
int[] batchUpdate(String sql, Map<String,?>[] batchValues)
本当の課題は、対応するMap<String, Object>
からList<Map<String, Object>>
の配列を取得することでした。次のコードを使用して、配列を取得し、バッチ更新を実行しました。
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<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);
わかりやすいことを願っています。ありがとう
@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;
}
宜しくお願いします