【问题标题】:How to do multiple inserts in database using spring JDBC Template batch?如何使用spring JDBC Template批处理在数据库中进行多次插入?
【发布时间】:2026-02-19 23:30:02
【问题描述】:

我需要一次性在数据库中插入数千条记录。我在我的应用程序中使用 spring JDBC 模板。

下面是我到目前为止编写的代码,它一次性执行所有插入。因此,如果我有 10,000 个用户,他们会一次性插入。但我想要的是分批执行它们,例如一批 500 条记录,依此类推。

@Override
public void saveBatch(final List<Employee> employeeList) {
    final int batchSize = 500;

    getJdbcTemplate().batchUpdate(QUERY_SAVE,
            new BatchPreparedStatementSetter() {
                @Override
                public void setValues(PreparedStatement ps, int i)
                        throws SQLException {
                    Employee employee = employeeList.get(i);
                    ps.setString(1, employee.getFirstname());
                    ps.setString(2, employee.getLastname());
                    ps.setString(3, employee.getEmployeeIdOnSourceSystem());
                }

                @Override
                public int getBatchSize() {
                    return employeeList.size();
                }
            });

}

如何更改上面的代码,以便我们可以将批量大小设置为 500,而不是 employeeList.size() 作为批量大小,执行它们,然后执行下一个 500 等等?

请帮忙。

【问题讨论】:

  • 我知道这个问题已经很老了,但我有一个问题。为什么不在getBatchSize 方法中直接返回 500?

标签: spring-jdbc


【解决方案1】:

我不确定您是否可以单独使用 JDBC 模板来做到这一点。也许您可以通过将大列表切成批量大小的块来逐步调用batchUpdate 方法。

看看这里:

@Override
public void saveBatch(final List<Employee> employeeList) {
    final int batchSize = 500;

    for (int j = 0; j < employeeList.size(); j += batchSize) {

        final List<Employee> batchList = employeeList.subList(j, j + batchSize > employeeList.size() ? employeeList.size() : j + batchSize);

        getJdbcTemplate().batchUpdate(QUERY_SAVE,
            new BatchPreparedStatementSetter() {
                @Override
                public void setValues(PreparedStatement ps, int i)
                        throws SQLException {
                    Employee employee = batchList.get(i);
                    ps.setString(1, employee.getFirstname());
                    ps.setString(2, employee.getLastname());
                    ps.setString(3, employee.getEmployeeIdOnSourceSystem());
                }

                @Override
                public int getBatchSize() {
                    return batchList.size();
                }
            });

    }
}

【讨论】:

  • 感谢您的回答,但我还有一个问题。如果有 100 个用户要插入,batchSize 给定 500,它会多次插入同一个用户的信息??
  • 如果有人想要返回 id,您可以通过 JdbcTemplate 直接访问 PreparedStatement:*.com/questions/7333524/…
【解决方案2】:

我知道这有点晚了,但你可以做一些类似于 @adarshr 正在做的事情,除了使用 Google Guava Lists.partition 来获取子列表。

public void saveBatch(final List<Employee> employeeList) {
    final int batchSize = 500;
    List<List<Employee>> batchLists = Lists.partition(employeeList, batchSize);

    for(List<Employee> batch : batchLists) {  
        getJdbcTemplate().batchUpdate(QUERY_SAVE, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i)
                    throws SQLException {
                Employee employee = batch.get(i);
                ps.setString(1, employee.getFirstname());
                ps.setString(2, employee.getLastname());
                ps.setString(3, employee.getEmployeeIdOnSourceSystem());
            }

            @Override
            public int getBatchSize() {
                return batch.size();
            }
        });
    }
}

【讨论】:

    【解决方案3】:

    仍然简化的方法是修改 getBatchsize() 方法,如下所示效果很好

    不需要分区或列表子集:),

    @Override
    public void saveBatch(final List<Employee> employeeList) {
        final int batchSize = 500;
        getJdbcTemplate().batchUpdate(QUERY_SAVE,
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i)
                            throws SQLException {
                        Employee employee = employeeList.get(i);
                        ps.setString(1, employee.getFirstname());
                        ps.setString(2, employee.getLastname());
                        ps.setString(3, employee.getEmployeeIdOnSourceSystem());
                    }
    
                    @Override
                    public int getBatchSize() {
                        if (batchSize > employeeList.size()) {
                            return employeeList.size();
                        }
                        return batchSize;
                    }
                });
    }
    

    【讨论】:

    • 这不起作用,但只会将前 500 条记录插入数据库。
    • 显式调用以batchsize为参数的batchUpdate方法 例如int[][] recordsUpdated = getJdbcTemplate().batchUpdate(QUERY_SAVE, employeeList, batchSize, ppss);
    【解决方案4】:

    Spring 提供了多个批处理的批处理操作。在下面的示例中,批量大小为 100。

     public class JdbcActorDao implements ActorDao {
    
        private JdbcTemplate jdbcTemplate;
    
        public void setDataSource(DataSource dataSource) {
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    
        public int[][] batchUpdate(final Collection<Actor> actors) {
            int[][] updateCounts = jdbcTemplate.batchUpdate(
                    "update t_actor set first_name = ?, last_name = ? where id = ?",
                    actors,
                    100,
                    new ParameterizedPreparedStatementSetter<Actor>() {
                        public void setValues(PreparedStatement ps, Actor argument) throws SQLException {
                            ps.setString(1, argument.getFirstName());
                            ps.setString(2, argument.getLastName());
                            ps.setLong(3, argument.getId().longValue());
                        }
                    });
            return updateCounts;
        }
    
        // ... additional methods
    
     }
    

    【讨论】:

    • 感谢您的回复。看起来干净多了。我有几个疑问:1)二维数组作为batchUpdate方法的响应是什么意思2)我们可以在应用程序运行期间交叉检查dboperations实际上是在批量运行吗?
    最近更新 更多