知识卡片
事务资源的锁升级问题,与请求事务 vs 延迟事务
内容
能被事务控制并发的不只是数据库,还包括消息队列、打印机、ATM等,统称”事务资源”——但这个词太拗口,日常讨论时通常仍直接说”数据库”泛指所有这类资源。现代事务系统为追求最大吞吐率,都会设计成尽量让事务保持短暂、尽量不跨越多个请求(跨请求的事务被称为长事务)。事务什么时候打开有两种常见策略:请求事务——请求开始时启动事务、请求结束时提交,简单直接、很多环境里只需把方法标记成”事务化”就能自动实现;延迟事务——尽可能晚打开事务,把读操作放在事务之外完成、只在真正要修改数据时才启动事务,好处是缩短了事务的持续时间,在启动事务和第一次写操作之间间隔较长时尤其能提升系统灵活性,代价是事务启动前完全没有并发控制,可能引发不一致读——因此通常只有在数据竞争特别激烈、或业务事务本身跨越多个请求时才值得这么做。使用事务时还必须清楚数据库实际锁住的粒度:多数情况下锁住的是被访问的具体行,允许多个事务同时访问同一张表;但如果一个事务锁住了太多行,数据库可能被迫把锁升级到整张表,从而把其他事务完全挡在外面——这正是不应该在领域的层超类型级别上使用一张通用”对象”表的原因:这种表极易触发锁升级,一旦被锁住,其余所有对数据库的访问都会被阻塞。
参考来源
- 位置:《企业应用架构模式》第一部分"表述"之"第5章 并发"之"5.5.2 事务资源"(源文件:_epub-src/OEBPS/Text/000036.html)
- 结论依据:原文说明"通常在请求开始时启动事务,在请求结束时提交事务……另一种方法是尽可能晚打开事务……如果一个事务锁住了一个表中的许多行,则数据库无法处理那么多锁,只能将锁升级到锁住整个表……这也正是为什么不能在领域的层超类型级别上使用'对象'表的原因",直接支撑本卡结论。
- 原始内容:这种锁升级(lock escalation)对并发有很大影响,这也正是为什么不能在领域的层超类型级别上使用"对象"表的原因。这样的表很容易就会导致锁升级,而锁住该表后其他对数据库的访问也就被阻塞了。