R2DBC 里 save() 为什么没写进去?没有事务时两条语句是同一个连接吗?事务里写 subscribe() 会怎样?连接池默认多大、满了会怎样?这篇在 Spring Boot 4.0.8 和本机 PostgreSQL 16 上逐个验证。
repo.save(...) 调用后不订阅:
库里 'lazy-no-sub' 的行数 = 0
repo.save(...).block():
返回的实体 id = 1,库里 'lazy-sub' 的行数 = 1
repo.findAll().count().block() = 1
db.sql("select name from users order by id").map(...).all().collectList().block() = [lazy-sub]调用 repository 方法不发 SQL,订阅才发。
无事务:第一条语句 pid=19925,第二条语句 pid=19925 无事务(再来一次):第一条语句 pid=19926,第二条语句 pid=19927 @Transactional:第一条语句 pid=19927,第二条语句 pid=19927 @Transactional(再来一次):第一条语句 pid=19927,第二条语句 pid=19927
事务外每条语句临时取连接,可能不是同一个;事务内绑定一个连接。
没有事务:保存两行再抛错 → 抛 IllegalStateException: boom
库里 name 以 'notx-' 开头的行数 = 2
@Transactional:保存两行再抛错 → 抛 IllegalStateException: boom
库里 name 以 'tx-' 开头的行数 = 0
TransactionalOperator:保存两行再抛错 → 抛 IllegalStateException: boom
库里 name 以 'op-' 开头的行数 = 0
@Transactional 里 subscribe() 一个没接到链上的 save,再抛错 → 抛 IllegalStateException: boom
库里 name 以 'forgot' 开头的行数 = 1
@Transactional 里把 save().block() 放到 boundedElastic 上,再抛错 → 抛 IllegalStateException: boom
库里 name 以 'block-inside' 开头的行数 = 1@Transactional 与 TransactionalOperator 能回滚;链外的 subscribe() / block() 不在事务里。
默认的 R2DBC 连接池:
30 个并发的 pg_sleep(300 ms):成功 30,失败 {},总用时 1100 ms
服务端同时存在的连接数最大值 = 10
spring.r2dbc.pool.max-size=3:
30 个并发的 pg_sleep(300 ms):成功 30,失败 {},总用时 3182 ms
服务端同时存在的连接数最大值 = 3
spring.r2dbc.pool.max-size=30:
30 个并发的 pg_sleep(300 ms):成功 30,失败 {},总用时 523 ms
服务端同时存在的连接数最大值 = 30
max-size=2、max-acquire-time=200ms,10 个并发的 pg_sleep(600 ms):
10 个并发的 pg_sleep(600 ms):成功 2,失败 {DataAccessResourceFailureException ← R2dbcTimeoutException ← TimeoutException=8},总用时 755 ms
服务端同时存在的连接数最大值 = 2默认 10 个连接,满了排队,可设 max-acquire-time。