当前位置: 首页 > 科技观察

MySQL锁机制的价值是什么?

时间:2023-03-14 09:16:57 科技观察

我们都知道MySQL中有各种锁,比如表锁、间隙锁、意向锁、行锁等等。但是你有没有想过:MySQL为什么会有锁机制,它存在哪些问题解决?今天我们就来说说这个问题。在没有锁的连环世界里,我们假设这样一个场景:王五账户里没有钱,向张三和李四借了100块钱,张三和李四欣然同意。如果此时数据库是串行的,没有并发执行线程,那么它的传输示意图如下。王五借贷串行执行-示意图从上图可以看出:在时间点1-2,数据库处理了张三的转账请求,读取到王五的账户余额为0,并向余额中添加100,此时时间,王五的账户余额为100。在时间点3-4,数据库处理了李四的转账请求,读取到王五的账户余额为100,将余额加100,此时王五的账户余额是200。最后,在时间点5,王五的账户余额为200元。可以看出王五的账户余额最终是200元,转账是没有问题的。这种数据库访问方式虽然可以保证数据的一致性,但是一次只能执行一个请求,并发访问性能太差。一个没有锁的并行世界为了提高数据库的并发访问性能,MySQL其实是支持多线程并发执行的。在我们上面的例子中,如果使用多线程并发处理,可能会存在如下图所示的情况。这种情况的处理流程可能是这样的:在时间点1,线程A读取到王五的账户余额为0。在时间点2,线程B读取到王五的账户余额为0。在时间点3,线程A给王五的账户余额加100,此时王五的账户余额为100。时间点4,线程B给王五账户余额增加100,此时王五账户余额为100。5/6时刻,线程A和B都写回了王五的余额,王五的账户余额为100。正常情况下,王五的最终账户余额应该是200元,但实际上王五的账户余额只有100元。通过分析上面的转账图,我们会发现问题的关键点在于时间4,此时王五的账户余额应该是100元,但是数据库线程B仍然认为王五的账户余额为0元,所以最终数据不一致。那么如何解决数据不一致的问题呢?答案是:锁机制。一个有锁的平行世界其实对于上面的转账例子,InnoDB中的处理流程如下图所示。时间点2,线程A读取到王五的账户余额为0。时间点3,线程B读取到王五的账户余额为0。时间点4,线程A将王五的账户余额加100,并获取锁。此时王五的账户余额为100,在时间5,线程B准备给王五的账户余额加100,但是此时发现王五的账户被锁了,于是阻塞等待.在时间点6,线程A提交事务。在时间点7,线程B重新读取王五的最新余额为100元,增加100元,最后在时间点8提交交易。在时间点4,数据库线程A锁定了王五的账户余额,并告诉其他线程:我正在更新这个数据,其余的人不要动。时间5,数据库线程B准备给王五的账户余额加100时,发现数据库线程A已经在运行,于是阻塞线程。数据库线程A提交事务并释放锁后,数据库线程B获取对应的锁。此时数据库线程B发现王五的账户余额为100,于是在100余额的基础上进行更新,然后提交交易,最终王五的账户余额为200元。提示:这个例子只是粗略的说明了InnoDB是如何通过锁来解决数据一致性问题的,有些细节你不用担心。例如,当事务隔离级别为READCOMMIT时,此示例有效,但REPEATABLEREAD隔离级别存在问题。看到这里,相信大家都明白了:锁的存在就是为了解决并发访问下数据不一致的问题。数据库之所以提供并发访问,是为了提高数据库的运行效率。