简介:事务策略 系列文章的作者 Mark Richards 将讨论如何在 Java 平台中为具有高吞吐 量和高用户并发性需求的应用程序实现事务策略。理解如何进行折衷将帮助您确保高水平的数据完整性和 一致性,并减少随后开发流程中的重构工作。
我在本 系列 的前几篇文章中所介绍的 API 层 和 客户端编排策略 事务策略是应用于大多数标准业 务应用程序的核心策略。它们简单、可靠、相对易于实现,并且提供了最高水平的数据完整性和一致性。 但有时,您可能需要减小事务的作用域以获取吞吐量、改善性能并提高数据库的并发性。您如何才能实现 这些目的,同时仍然维持高水平的数据完整性和一致性呢?答案是使用 High Concurrency 事务策略。
High Concurrency 策略源自 API 层 策略。API 层策略虽然非常坚固和可靠,但它存在一些缺点。始 终在调用栈的最高层(API 层)启动事务有时会效率低下,特别是对于具有高用户吞吐量和高数据库并发 性需求的应用程序。限制特定的业务需求,长时间占用事务和长时间锁定都会消耗过多资源。
与 API 层策略类似,High Concurrency 策略释放了客户机层的任何事务责任。但是,这还意味着, 您只能通过客户机层调用一次任何特定的逻辑工作单元(LUW)。High Concurrency 策略旨在减小事务的 总体作用域,以便资源锁定的时间更短,从而增加应用程序的吞吐量、并发性以及性能。
通过使用此策略所获取的好处在一定程度上将由您所使用的数据库以及它所采用的配置决定。一些数 据库(比如说使用 InnoDB 引擎的 Oracle 和 MySQL)不会保留读取锁,而其他数据库(比如没有 Snapshot Isolation Level 的 SQL Server)则与之相反。保留的锁越多,无论它们是共享还是专用的, 它们对数据库(以及应用程序)的并发性、性能和吞吐量的影响就越大。
但是,获取并在数据库中保留锁仅仅是高并发性任务的一个部分。并发性和吞吐量还与您释放锁的时 间有关。无论您使用何种数据库,不必要地长时间占用事务将更长地保留共享和专用锁。在高并发性下, 这可能会造成数据库将锁级别从低级锁提高到页面级锁,并且在一些极端情况下,从页面级锁切换到表级 锁。在多数情况下,您无法控制数据引擎用于选择何时升级锁级别的启发方法。一些数据库(比如 SQL Server)允许您禁用页面级锁,以期它不会从行级锁切换到表级锁。有时,这种赌博有用,但大多数情况 下,您都不会实现预期中的并发性改善。
底线是,在高数据库并发性的场景中,数据库锁定(共享或专用)的时间越长,则越有可能出现以下 问题:
数据库连接耗尽,从而造成应用程序处于等待状态
由共享和专用锁造成的死锁,从而造成性能较差以及事务失败
从页面级锁升级到表级锁
换句话说,应用程序在数据库中所处的时间越长,应用程序能处理的并发性就越低。我所列出的任何 问题都会造成您的应用程序运行缓慢,并且将直接减少总体吞吐量和降低性能 — 以及应用程序处理大型 并发性用户负载的能力。