MySQL 5.7.20通过Spring JdbcTemplate调用SELECT FOUND_ROWS()返回结果异常
解决Spring JdbcTemplate中SELECT FOUND_ROWS()返回结果不正确的问题
这个问题我之前帮不少开发者排查过,核心原因确实和你猜测的一致——连接池的连接分配机制导致SELECT FOUND_ROWS()与目标查询不在同一个数据库连接上执行。MySQL的FOUND_ROWS()是基于当前连接的上下文来返回结果的,一旦两次操作分到不同连接,自然会拿到错误的结果。下面给你几个可靠的解决方案:
方案1:将两个操作绑定到同一个事务中
Spring的事务机制会保证同一个事务内的所有数据库操作都使用同一个连接。你可以用TransactionTemplate或者声明式事务(@Transactional)来包裹目标查询和FOUND_ROWS()的调用:
使用TransactionTemplate的示例代码:
// 注入TransactionManager和JdbcTemplate @Autowired private PlatformTransactionManager transactionManager; @Autowired private JdbcTemplate jdbcTemplate; public Long queryWithTotalRows() { TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); return transactionTemplate.execute(status -> { // 第一步:执行带SQL_CALC_FOUND_ROWS的目标查询(必须加这个关键字) jdbcTemplate.query("SELECT SQL_CALC_FOUND_ROWS * FROM your_table WHERE your_condition LIMIT 10", rs -> { // 处理查询结果集,比如映射为实体类 }); // 第二步:在同一个连接下执行FOUND_ROWS() return jdbcTemplate.queryForObject("SELECT FOUND_ROWS()", Long.class); }); }
使用声明式事务的示例:
@Autowired private JdbcTemplate jdbcTemplate; @Transactional public Long queryWithTotalRows() { // 执行目标查询 jdbcTemplate.query("SELECT SQL_CALC_FOUND_ROWS * FROM your_table WHERE your_condition LIMIT 10", rs -> { // 处理结果 }); // 执行FOUND_ROWS() return jdbcTemplate.queryForObject("SELECT FOUND_ROWS()", Long.class); }
方案2:直接使用ConnectionCallback控制同一个连接
如果不想引入事务,可以通过JdbcTemplate的ConnectionCallback接口直接获取同一个连接,手动执行两个语句:
@Autowired private JdbcTemplate jdbcTemplate; public Long queryWithTotalRows() { return jdbcTemplate.execute((ConnectionCallback<Long>) conn -> { // 执行目标查询 try (PreparedStatement ps = conn.prepareStatement("SELECT SQL_CALC_FOUND_ROWS * FROM your_table WHERE your_condition LIMIT 10")) { try (ResultSet rs = ps.executeQuery()) { // 处理结果集 while (rs.next()) { // 读取数据 } } } // 同一个连接下执行FOUND_ROWS() try (PreparedStatement ps = conn.prepareStatement("SELECT FOUND_ROWS()")) { try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return rs.getLong(1); } return 0L; } } }); }
关键注意事项
- 必须在目标查询中添加
SQL_CALC_FOUND_ROWS关键字,否则FOUND_ROWS()只会返回当前查询的行数(即LIMIT限制的数量),而不是忽略LIMIT后的总行数。 - 避免在目标查询和
FOUND_ROWS()之间执行其他数据库操作,否则会覆盖当前连接的上下文,导致结果不准确。
内容的提问来源于stack exchange,提问作者user3127996
相关产品推荐
相关产品推荐

