JdbcTemplate 查不到行会抛什么异常?BeanPropertyRowMapper 列名对不上会不会报错?IN 列表是空的怎么办?batchUpdate 真的把 SQL 合并了吗?update 返回的行数是什么意思?这篇在 Spring Framework 7、HikariCP、MySQL 上逐个实测。
queryForObject("select count(*) from person", Integer.class) ⇒ 3
queryForObject 没有匹配的行 ⇒ 抛 EmptyResultDataAccessException:Incorrect result size: expected 1, actual 0
queryForObject 有 2 行匹配 ⇒ 抛 IncorrectResultSizeDataAccessException:Incorrect result size: expected 1, actual 2
queryForObject 返回 null 列(email 为 NULL) ⇒ null
query(sql, RowMapper) 手写 lambda ⇒ 2 行 [Ann#0, Bob#1]
BeanPropertyRowMapper<Person>(下划线列名 → 驼峰属性) ⇒ 3 行 [Person[1,Ann Lee,30,ann@x], Person[2,Bob Lee,25,null], Person[3,Cid Ray,41,cid@x]]
DataClassRowMapper<PersonRec>(record) ⇒ 3 行 [PersonRec[id=1, firstName=Ann, lastName=Lee, age=30, email=ann@x], PersonRec[id=2, firstName=Bob, lastName=Lee, age=25, email=null], PersonRec[id=3, firstName=Cid, lastName=Ray, age=41, email=cid@x]]
BeanPropertyRowMapper,但 select 里把 first_name 改名成 fname ⇒ 1 行 [Person[1,null Lee,30,ann@x]]
JdbcClient:sql(...).param(...).query(Person.class).list() ⇒ 2 行 [Person[1,Ann Lee,30,ann@x], Person[2,Bob Lee,25,null]]
JdbcClient:单值 .query(String.class).single() 没有匹配的行 ⇒ 抛 EmptyResultDataAccessException:Incorrect result size: expected 1, actual 0
JdbcClient:.optional() ⇒ Optional.emptyqueryForObject 0 行与多行分别抛不同异常;BeanPropertyRowMapper 下划线转驼峰,对不上的列静默忽略;JdbcClient 有 single 和 optional。
命名参数:where last_name = :ln and age > :age ⇒ 1 行 [Ann] IN 列表展开:id in (:ids),传入 List.of(1, 3) ⇒ 2 行 [Ann, Cid] IN 列表是空集合 ⇒ 抛 BadSqlGrammarException:PreparedStatementCallback; bad SQL grammar [select first_name from person where id in ()] 同一个命名参数用两次 ⇒ 1 行 [Cid] 少传了一个命名参数 ⇒ 抛 InvalidDataAccessApiUsageException:No value supplied for the SQL parameter 'age': No value registered for key 'age' BeanPropertySqlParameterSource(从对象取参数) ⇒ 1 行 [Cid]
IN 列表自动展开,空集合变成语法错误;漏传参数明确报错。
循环里一行一个 update:中位 614 ms;服务端执行的 INSERT 语句数 Com_insert +5000;表里 5000 行 batchUpdate(sql, List<Object[]>):中位 517 ms;服务端执行的 INSERT 语句数 Com_insert +5000;表里 5000 行 NamedParameterJdbcTemplate.batchUpdate(sql, SqlParameterSource[]):中位 499 ms;服务端执行的 INSERT 语句数 Com_insert +5000;表里 5000 行
默认 MySQL 参数下 batchUpdate 只省往返,不合并语句。
第一次 update person set email = 'new@x' where id = 1(值确实变了) ⇒ 1 第二次执行同一条(值没有变) ⇒ 1 update 不存在的 id ⇒ 0 GeneratedKeyHolder 取自增主键 ⇒ 新行 id = 4 省了 RETURN_GENERATED_KEYS ⇒ 抛 TransientDataAccessResourceException:PreparedStatementCallback; Generated keys not requested. You need to specify Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate(), Statement.executeLargeUpdate() or Connection.prepareStatement(… 上一条抛了异常,但那行 Eve 是不是已经插进去了(auto-commit) ⇒ person 里 first_name='Eve' 的行数 = 1 JdbcClient:.update(keyHolder) ⇒ 影响 1 行,新行 id = 6
update 返回匹配的行数;取自增主键要 RETURN_GENERATED_KEYS,否则 INSERT 先执行后抛异常。