@SuppressWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
    void saveBatchStatisticValueSource_String(final List<SQLStatValSourceDO> batch) {
        final LogExecutionTime logExecutionTime = new LogExecutionTime();

        try (final Connection connection = getConnection()) {
            final StringBuilder sql = new StringBuilder();
            sql.append(INSERT_WITHOUT_VALUES);
            boolean doneOne = false;
            for (final SQLStatValSourceDO item : batch) {
                if (doneOne) {
                    sql.append(",");
                }
                sql.append("(");
                sql.append(item.getCreateMs());
                sql.append(",'");
                sql.append(SQLSafe.escapeChars(item.getName())); // must escape
                // any bad chars as we risk sql injection (not an issue for prepared statements)
                sql.append("',");
                sql.append(item.getType().getPrimitiveValue());
                sql.append(",");
                sql.append(item.getValueSum().orElse(0));
                sql.append(",");
                sql.append(item.getCount());
                sql.append(")");
                doneOne = true;
            }

            try (final Statement statement = connection.createStatement()) {
                statement.executeUpdate(sql.toString());

                if (LOGGER.isDebugEnabled()) {
                    logDurationToDebug("saveBatchStatisticValueSource_String", batch, logExecutionTime);
                }
            }
        } catch (final SQLException sqlEx) {
            throw new RuntimeException(sqlEx);
        }
    }
Inserts the batch using a single big non-prepared statement.
As it is non-prepared we need to manually escape chars else risk SQL injection.
stroom-statistics/stroom-statistics-impl-sql/src/main/java/stroom/statistics/impl/sql/SQLStatisticValueBatchSaveService.java