Spring与MariaDB:批量事务删插时如何让查询获取已提交旧数据
解决方案:通过事务隔离级别实现无阻塞的旧数据读取
核心目标是让查询操作读取事务开始前的已提交快照数据,避免被批处理的写事务阻塞,同时保证批处理的原子性。以下分不同数据库给出具体配置方案:
通用原则
- 批处理作业的事务只需保持默认的原子性隔离级别(
REPEATABLE READ或READ COMMITTED),即可保证「删除全表+插入新数据」的原子性(要么全部成功,要么全部回滚)。 - 查询API必须使用支持快照读的隔离级别,避免加读锁,从而直接读取旧的已提交数据,不等待写锁释放。
MySQL/MariaDB 配置
- 批处理作业:无需修改隔离级别,保持默认的
REPEATABLE READ即可,确保删插操作在原子事务中执行。 - 查询API:在查询前设置会话级隔离级别为
READ COMMITTED(或保持默认的REPEATABLE READ),InnoDB在这两个级别下的普通查询均为快照读,不会被写事务阻塞:
即使批处理事务正在执行删插,查询也会读取事务开始前的已提交快照数据,无阻塞、无超时。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT * FROM A;
PostgreSQL 配置
- 批处理作业:使用默认的
READ COMMITTED隔离级别,即可保证删插操作的原子性。 - 查询API:设置隔离级别为
READ COMMITTED(默认)或SNAPSHOT ISOLATION:
读已提交级别下,每次查询都会获取当前最新的已提交数据;若批处理事务未提交,则自动读取旧的已提交快照,全程无阻塞。SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT * FROM A;
SQL Server 配置
- 先开启数据库快照特性(只需执行一次):
ALTER DATABASE YourDatabase SET ALLOW_SNAPSHOT_ISOLATION ON; ALTER DATABASE YourDatabase SET READ_COMMITTED_SNAPSHOT ON; - 批处理作业:保持默认的
READ COMMITTED隔离级别,确保原子性。 - 查询API:设置隔离级别为
READ COMMITTED(开启快照后自动使用快照读)或SNAPSHOT:
配置完成后,查询不会加锁,直接读取已提交的快照数据,完全避免被批处理的写事务阻塞。SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT * FROM A;
注意事项
- 禁止使用
READ UNCOMMITTED隔离级别:该级别会读取未提交的数据,不符合「获取旧的已提交数据」的需求。 - 尽量缩短批处理事务的执行时间:减少快照数据的留存时长,降低数据库的存储和性能压力。
- 部分数据库可根据实际负载调整快照相关参数(如MySQL的
innodb_max_undo_log_size),默认配置通常可满足常规场景需求。
内容的提问来源于stack exchange,提问作者bboy
相关产品推荐
相关产品推荐

