如何基于Spring JDBC实现存储过程的批量调用?
当然有更高效的办法啦!不用傻乎乎循环调用100次存储过程,Spring JDBC给咱们提供了几种优雅的批量调用方案,下面给你两个实用的思路:
方案一:直接用JdbcTemplate的batchUpdate批量调用
咱们自定义的StoredProcedure子类底层其实也是依赖JdbcTemplate的,所以完全可以跳过子类,直接用JdbcTemplate的批量更新能力来调用存储过程,步骤很简单:
- 先写好存储过程的调用SQL,比如你的存储过程叫
batch_insert_data,需要传id和name两个参数,那SQL就是CALL batch_insert_data(?, ?)(注意不同数据库语法略有差别,比如Oracle得写成BEGIN batch_insert_data(:id, :name); END;)。 - 把要批量插入的数据转换成参数数组列表,每个数组对应一次存储过程调用的参数。
- 调用
JdbcTemplate.batchUpdate()执行批量操作就行。
给你贴个代码示例:
@Autowired private JdbcTemplate jdbcTemplate; public void batchInsertData(List<YourDataPO> dataList) { // 构造存储过程调用语句,根据你的数据库调整语法 String callSql = "CALL batch_insert_data(?, ?)"; // 把业务对象转成存储过程需要的参数数组 List<Object[]> batchParams = dataList.stream() .map(data -> new Object[]{data.getId(), data.getUserName()}) .collect(Collectors.toList()); // 执行批量调用,返回每个调用的影响行数 int[] updateResults = jdbcTemplate.batchUpdate(callSql, batchParams); // 可以遍历结果做校验,比如判断每个调用是否成功 for (int result : updateResults) { if (result <= 0) { // 处理调用失败的情况 } } }
方案二:扩展现有StoredProcedure子类支持批量执行
如果你不想放弃已经写好的StoredProcedure子类,也可以给它加个批量执行的方法,内部还是借助JdbcTemplate的能力来实现。
假设你已经有个UserInsertProcedure类继承自StoredProcedure,可以这么扩展:
public class UserInsertProcedure extends StoredProcedure { public UserInsertProcedure(JdbcTemplate jdbcTemplate) { super(jdbcTemplate, "batch_insert_data"); // 声明存储过程的输入参数,类型要和数据库对应 declareParameter(new SqlParameter("user_id", Types.INTEGER)); declareParameter(new SqlParameter("user_name", Types.VARCHAR)); compile(); } // 原来的单次执行方法 public Map<String, Object> execute(Integer userId, String userName) { Map<String, Object> params = new HashMap<>(); params.put("user_id", userId); params.put("user_name", userName); return super.execute(params); } // 新增的批量执行方法 public void batchExecute(List<YourDataPO> dataList) { // 把业务对象转成存储过程需要的参数Map列表 List<Map<String, Object>> batchParams = dataList.stream() .map(data -> { Map<String, Object> params = new HashMap<>(); params.put("user_id", data.getId()); params.put("user_name", data.getUserName()); return params; }) .collect(Collectors.toList()); // 调用JdbcTemplate的batchUpdate,手动设置参数 getJdbcTemplate().batchUpdate( getSql(), batchParams, new ParameterizedPreparedStatementSetter<Map<String, Object>>() { @Override public void setValues(PreparedStatement ps, Map<String, Object> params) throws SQLException { // 按照参数声明的顺序设置值 ps.setInt(1, (Integer) params.get("user_id")); ps.setString(2, (String) params.get("user_name")); } } ); } }
几个要注意的点
- 数据库语法差异:一定要根据你的数据库调整存储过程的调用SQL,比如MySQL用
CALL,Oracle用BEGIN...END包裹。 - 输出参数处理:如果你的存储过程有输出参数,批量处理时得用
CallableStatement来处理,这时候可以用JdbcTemplate.batchUpdate()的另一个重载,传入CallableStatementCreator来处理输出参数。 - 性能优势:批量调用相比循环单次调用,能大幅减少和数据库的网络往返次数,数据量越大,性能提升越明显。
内容的提问来源于stack exchange,提问作者user902383
相关产品推荐
相关产品推荐

