@Transactional
@NonNull
@VisibleForTesting
ImportFileActivityOutput processDbOperation(@NonNull final ImportFileActivityInput input) {
if (input.dataAction().equals(OVERWRITE)) {
final var truncateQuery =
"TRUNCATE TABLE \"%s\".\"%s\" RESTART IDENTITY CASCADE".formatted(SCHEMA, input.tableName());
try {
jdbcTemplate.execute(truncateQuery);
} catch (DataAccessException e) {
throw new IllegalStateException("Error executing truncate", e);
}
log.atInfo().addKeyValue("tableName", input.tableName()).log("Truncated table successfully");
}
convertImportFile(input.file(), input.requiredColumns(), input.delimiter())
.toStream()
.forEach(batch -> {
final var allRowsEmpty = batch.stream()
.allMatch(row -> row.values().stream().allMatch(value -> value == null || value.isBlank()));
if (allRowsEmpty) {
log.atInfo().addKeyValue("tableName", input.tableName()).log("No data to add for table");
return;
}
final var columnNames = new ArrayList<>(batch.get(0).keySet());
final var formattedColumnNames =
columnNames.stream().map(col -> "\"" + col + "\"").collect(joining(", "));
final var queryPlaceholders =
columnNames.stream().map(col -> "?").collect(joining(", "));
final var primaryKeys =
Optional.ofNullable(input.primaryKeys()).orElse(emptyList());
final var conflictColumns =
primaryKeys.stream().map(pk -> "\"" + pk + "\"").collect(joining(", ", "(", ")"));
final var updateClause = columnNames.stream()
.filter(col -> !primaryKeys.contains(col))
.map(col -> "\"" + col + "\" = EXCLUDED.\"" + col + "\"")
.collect(joining(", "));
final var query =
switch (input.dataAction()) {
case ADD -> "INSERT INTO \"%s\".\"%s\" (%s) VALUES (%s) ON CONFLICT %s DO NOTHING"
.formatted(
SCHEMA,
input.tableName(),
formattedColumnNames,
queryPlaceholders,
conflictColumns);
case ADD_UPDATE -> """
INSERT INTO "%s"."%s" (%s) VALUES (%s) \
ON CONFLICT %s DO UPDATE SET %s"""
.formatted(
SCHEMA,
input.tableName(),
formattedColumnNames,
queryPlaceholders,
conflictColumns,
updateClause);
case OVERWRITE -> "INSERT INTO \"%s\".\"%s\" (%s) VALUES (%s)"
.formatted(SCHEMA, input.tableName(), formattedColumnNames, queryPlaceholders);
default -> throw new IllegalStateException("Invalid request type");
};
final var batchArgs = batch.stream()
.map(row -> columnNames.stream().map(row::get).toArray(Object[]::new))
.toList();
try {
jdbcTemplate.batchUpdate(query, batchArgs);
} catch (DataAccessException e) {
log.atError()
.addKeyValue("tableName", input.tableName())
.setCause(e)
.log("error during " + input.dataAction() + " operation");
throw new IllegalStateException("Error executing batch " + input.dataAction(), e);
}
});
log.atInfo().addKeyValue("tableName", input.tableName()).log("Completed " + input.dataAction() + " operation");
return new ImportFileActivityOutput(
input.automationId(),
ActivityStatus.SUCCESS,
input.dataAction() + " complete for table: " + input.tableName());
}
这是我目前正在执行查询的方式。我正在进行串联串联,这将导致SQL注入攻击,因此我正在使用@suppressfbresfbwarnings(“ secsqlisprjdbc”)。我的问题是,我需要修改我的查询以使用准备好的陈述来防止需要抑制注射警告,而根本不必担心注射攻击。 “批次”是列表>。谢谢!
jdbcTemplate.query(
"TRUNCATE TABLE ?.? RESTART IDENTITY CASCADE",
new PreparedStatementSetter() {
public void setValues(PreparedStatement preparedStatement) throws
SQLException {
preparedStatement.setString(1, SCHEMA);
preparedStatement.setString(2, input.tableName());
}
});