lamp网站开发黄金组合,适合大型网站的流量套餐,成都网站建设有哪些,深圳工业设计公司有哪些使用时间戳的并发控制 专栏内容#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发#xff0c;开发的步骤#xff0c;以及开发过程中的涉及的原理#xff0c;遇到的问题等#xff0c;让大家能跟上并且可以一起开发#xff0c;让每个需要的人成为参与者。 本专栏会…使用时间戳的并发控制 专栏内容 手写数据库toadb 本专栏主要介绍如何从零开发开发的步骤以及开发过程中的涉及的原理遇到的问题等让大家能跟上并且可以一起开发让每个需要的人成为参与者。 本专栏会定期更新对应的代码也会定期更新每个阶段的代码会打上tag方便阶段学习。 开源贡献 toadb开源库 个人主页我的主页 管理社区开源数据库 座右铭天行健君子以自强不息地势坤君子以厚德载物. 文章目录 使用时间戳的并发控制前言概述时间戳介绍记录时间戳的方法事务提交的记录 可以解决的问题过晚的读过晚的写脏数据的问题mysql中的表现 基于时间戳调度的规则调度器选择读写请求的处理 多版本时间戳时间戳与封锁总结结尾 前言
随着信息技术的飞速发展数据已经渗透到各个领域成为现代社会最重要的资产之一。在这个大数据时代数据库理论在数据管理、存储和处理中发挥着至关重要的作用。然而很多读者可能对数据库理论感到困惑不知道如何选择合适的数据库如何设计有效的数据库结构以及如何处理和管理大量的数据。因此本专栏旨在为读者提供一套全面、深入的数据库理论指南帮助他们更好地理解和应用数据库技术。
数据库理论是研究如何有效地管理、存储和检索数据的学科。在现代信息化社会中数据量呈指数级增长如何高效地处理和管理这些数据成为一个重要的问题。同时随着云计算、物联网、大数据等新兴技术的不断发展数据库理论的重要性日益凸显。
因此本专栏的分享希望可以提高大家对数据库理论的认识和理解对于感兴趣的朋友带来帮助。
概述
在数据库中如何保证并发事务时数据的一致性也就是可串行化会有采用调度器来进行协调各事务中动作的顺序以衣是否可以执行等。调度器采用的模型主要有几种
基于封锁的调度模型基于时间戳的调度模型基于有效性确认的调度模型
前几篇博文中分享了基于封锁的调度模型本文主要介绍基于时间戳的调度模型主要从时间戳的概念可以保证的行为和存在的问题调度规则以及多版本的优化与封锁模型的联合使用等方面进行介绍。
时间戳介绍
也就是记录上次读和写每个数据库元素的事务时间点同时每个事务也有一个时间戳记录它的开始时间点。
当有事务要请求该数据库元素时比较这两个时间根据事务的时间戳来调度来确保串行调度。
记录时间戳的方法 理论上当多个事务开始的时间间隔大于时间最小计数时使用时间来记录是可以达到目标的但是往往时间的精度不足以记录多个同时开始的事务。 调度器维护一个计时器。每当一个事务开始时计数器就加1而新值成为该事务的时间戳。这种方法与时间无关但是它们具有时间的特性单调递增不会重复总是保证晚的事务比开始早的事务具有更高的时间戳
事务提交的记录
当一个事务T读到另一事务U所写的数据这一行为也是符合串行化规则但是事务U最后中止了并没有提交这样事务T读到的是脏数据这一问题肯定会导致数据库状态变得不一致这是任何调度器都要防止的脏读。
除了两个事务和数据库元素上的时间戳外还需要记录一个事务的提交状态位当事务没有提交时调度器也需要阻止其它事务的访问请求。
可以解决的问题
假如事务在开始的那一时刻就立即执行结束那也就不会发生非可串行化的问题。往往事务中的各个动作都会持续一段时间这就会过晚读和过晚写的问题发生而当事务中止时读取的此事务写的数据就会发生脏读的情况。
过晚的读
问题描述 事务执行的时间轴是这样的 如图所示事务T的读在事务U的写之后而事务U的开始时间晚于事务T这就导致事务T读到的数据不一致。
解决方法 当事务T的进行读请求时发现当前数据元素上的时间戳晚于自己的事务开始时间戳时事务T应该是需要中止它什么都不能做了。
过晚的写
问题描述 事务执行的时间轴是这样的 如图所示事务U开始时间晚于事务T而事务U的读操作早于事务T本应该事务U可以读到T写入的值但是T的写入更晚。
解决方法 事务T因为时间戳晚于数据元素上的时间戳也就是事务U访问的时间戳应该中止事务T让事务U可以读取正确的数据。
脏数据的问题
事务提交标志的设置就是用来解决这个问题的先来看两个问题。 问题一 |事务U | 事务T| |:–|:–| |begin; || |write(X) | | || begin;| ||read(X)| |abort|| ||commit;| 问题二 |事务U | 事务T| |:–|:–| |begin; || |write(X) | | || begin;| ||write(X)| ||commit;| |abort||
对于问题一因为事务U在事务T之前启动并写入X所有事务T读取X是符合上面时间戳的规则但是当事务U最终中止时事务T读取的X就是脏数据是数据库中本不存在的数据
对于问题二有趣的事情来了此时事务T提交后其实它是基于事务U的比如X1事务U写入后X2, 事务T写入后X3那么提交成功后X3而事务U回滚后好像什么都不需要做还是事务U回滚为X1事务T重新再做一遍呢
解决方法 对于问题一的此类问题请求读操作时需要看当前数据元素是否已经提交如果没有提交需要中止当前请求或推迟到该数据库元素提交之后再处理。
而对于问题二的此类问题写操作请求时也同样需要判断当前数据元素是否已经提交如果没有提交需要中止当前请求或推迟到该数据库元素提交之后再处理。 当然更晚的写也可以什么都不做这被称为Thomas写法则最后事务U中止后它要回退它的写入和数据库元素上的时间戳但是事务T的写入被跳过了同时也提交完成了此时想恢复事务T的操作已经不可能了。
mysql中的表现
mysql show variables like transaction%;
---------------------------------------------------
| Variable_name | Value |
---------------------------------------------------
| transaction_alloc_block_size | 8192 |
| transaction_allow_batching | OFF |
| transaction_isolation | REPEATABLE-READ |
| transaction_prealloc_size | 4096 |
| transaction_read_only | OFF |
| transaction_write_set_extraction | XXHASH64 |
---------------------------------------------------
6 rows in set (0.00 sec)
mysql begin;
Query OK, 0 rows affected (0.00 sec)mysql select * from test_concurrent;
------
| i |
------
| 5 |
------
1 row in set (0.00 sec)
-- 这此时另外启动一个事务将i修改为6,并提交事务
mysql select * from test_concurrent;
------
| i |
------
| 5 |
------
1 row in set (0.00 sec)mysql update test_concurrent set i 3 where i 5;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0mysql commit;
Query OK, 0 rows affected (0.00 sec)mysql select * from test_concurrent;
------
| i |
------
| 6 |
------
1 row in set (0.00 sec)
可以看到mysql中当前事务可以看到i5但确修改不成功返回0 rows被updated这就是一个很迷惑的现象。
基于时间戳调度的规则
经过上面问题的分析现在我们概括基于时间戳调度的规则。
调度器选择
对于来自事务的读写操作请求调度器有几种选择
同意该请求推迟请求中止请求事务
读写请求的处理
调度器收到读写操作请求
收到读操作请求时检查当前数据库元素上次操作事务的提交状态 如果已经提交则再检查时间戳的先后顺序如果请求事务的时间戳大于当前数据元素的时间戳则可以同意请求并将时间戳更新为当前事务如果事务时间戳小于当前数据元素的时间戳则需要中止如果尚未提交则请求事务需要推迟 当收到写操作请求时先检查当前事务与数据库元素上的时间戳 如果请求事务的时间戳大于当前数据元素的时间戳再检查数据元素上次操作的事务是否提交如果已经提交则同意本次写请求如果未提交则需要推迟本次请求如果事务时间戳小于当前数据元素的时间戳本次请求事务需要中止 当收到事务提交请求时更新数据元素上的提交状态同时唤醒等待的事务请求 当收到事务T中止请求时那么回退事务T对应的所有操作数据等待的事务需要重新发起读或写请求因为需要检查事务T的写被中止后是否合法。
多版本时间戳
基于时间戳的并发控制调度器如上面介绍的会存在读写之间冲突所以在这个基础上进行了一个重要的演进就是同时保留数据库元素的多个带不同时间戳的版本使得读写可以同时进行。
多版本时间戳的流程与上面流程类似
当收到写操作请求时WT(X)如果请求被同意那么X的一个新版本Xi被创建它的时间戳为Ti(X);此时收到一个读操作请求时RU(X)时最新版本检查不通过时查找时间戳小于事务U的版本X也是就WT(X)执行前的版本就是当前可读的版本同意RU(X)在版本X上的读请求数据元素的时间戳与对应的版本有关当然再有事务的写请求来时还是需要在最后的版本Xi上处理旧版本的清理当X的某个版本上的时间戳小于任何当前活跃事务的时间戳时就可以清理掉它了。
多版本时间戳的方式解决了读写并发时的性能问题。
时间戳与封锁
在大多数只读事务或者并发读写同一元素的情况不频繁时基于时间戳的调度比较有优势
而当读写并发比较高而且对同一数据库元素竞争较大时封锁调度反而比较优因为此种情况下基于时间戳的调度需要进行频繁的回退操作。
在现代商用数据库中会将事务分为只读事务和读写事务在只读事务时只使用时间戳的方式而只读事务时采用两阶段锁的方式。
总结
基于时间戳的调度模型可以说是一种乐观的模型它假设没有非可串行化行为发生并且只有在违例发生时才会进行修正或者中止。与此相反封锁的调度模型是假设非可串行化行为一定会发生那么提前进行预防并且推迟可能发生的事务但不中止它们它是一种悲观模型。
这两种模型如果对于大量只读操作时乐观型好于悲观型调度器。
结尾 非常感谢大家的支持在浏览的同时别忘了留下您宝贵的评论如果觉得值得鼓励请点赞收藏我会更加努力 作者邮箱studysenllang.onaliyun.com 如有错误或者疏漏欢迎指出互相学习。