同一数据表多进程读写事务的数据库并发处理疑问
关于未提交写事务与并发读事务的行为分析
这个问题直击数据库并发控制的核心场景——答案完全取决于你所使用的数据库事务隔离级别,不同的配置会带来截然不同的结果,下面我逐个拆解常见隔离级别对应的行为:
1. 读未提交(Read Uncommitted)
这是最宽松的隔离级别,在这种设置下:
- P2会直接读取到P1未提交的修改内容,也就是我们常说的「脏读」(Dirty Read)
- 举个例子:P1插入了一条
user记录但还没提交,P2此时查询user表就能看到这条未提交的记录;如果后续P1回滚了事务,P2之前读到的数据就变成了不存在的「脏数据」
2. 读已提交(Read Committed)
这是PostgreSQL、SQL Server等数据库的默认隔离级别,行为如下:
- P2不会读取到P1未提交的修改,它只能看到P1提交前的数据库快照(不同数据库实现略有差异,比如InnoDB会为每次查询生成一个快照)
- 若P1正在修改某几行数据,P2读取这些行时,要么直接获取修改前的快照版本(无需等待),要么在少数锁机制实现的数据库中短暂等待P1释放行锁,但绝不会读到未提交内容
- 这种级别可以避免脏读,但可能出现「不可重复读」(同一事务内两次读同一行,结果不同)
3. 可重复读(Repeatable Read)
这是MySQL InnoDB的默认隔离级别,规则更严格:
- P2在整个读事务期间,都会基于事务开始时的数据库快照进行读取
- 不管P1的写事务是否提交,P2都看不到P1的任何修改,直到自己的读事务结束
- 这种级别可以避免脏读和不可重复读,但可能出现「幻读」(同一事务内两次查询同一范围,结果行数不同)
4. 串行化(Serializable)
这是最严格的隔离级别,完全避免所有并发问题:
- P2的读事务会被P1的写事务阻塞,直到P1提交或回滚后,P2才能继续执行读取操作
- 本质上是把所有事务按顺序执行,彻底消除并发冲突,但牺牲了部分性能
额外补充:关于表锁定的疑问
现代关系型数据库(比如MySQL、PostgreSQL)默认使用行级锁而非表级锁,所以:
- 除非P1执行的是会触发表级锁的操作(比如不带索引的批量更新、
LOCK TABLE语句),否则P2读取未被P1修改的行时完全不受影响 - 只有当P2读取被P1修改的特定行时,才会触发上面隔离级别对应的行为
总结一下:没有统一的答案,核心看你的数据库事务隔离级别配置,以及数据库对该级别的具体实现。
内容的提问来源于stack exchange,提问作者LookIntoEast
相关产品推荐
相关产品推荐

