【数据库】基于时间戳的并发访问控制,乐观模式,时间戳替代形式及存在的问题,与封锁模式的对比

使用时间戳的并发控制

专栏内容

  • 手写数据库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的,比如X=1,事务U写入后X=2, 事务T写入后X=3,那么提交成功后X=3;而事务U回滚后,好像什么都不需要做,还是事务U回滚为X=1,事务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中,当前事务可以看到i=5,但确修改不成功,返回0 rows被updated,这就是一个很迷惑的现象。

基于时间戳调度的规则

经过上面问题的分析,现在我们概括基于时间戳调度的规则。

调度器选择

对于来自事务的读写操作请求,调度器有几种选择:

  • 同意该请求
  • 推迟请求
  • 中止请求事务

读写请求的处理

调度器收到读写操作请求,

  1. 收到读操作请求时,检查当前数据库元素上次操作事务的提交状态,
  • 如果已经提交,则再检查时间戳的先后顺序,如果请求事务的时间戳大于当前数据元素的时间戳,则可以同意请求,并将时间戳更新为当前事务;如果事务时间戳小于当前数据元素的时间戳,则需要中止;
  • 如果尚未提交,则请求事务需要推迟;
  1. 当收到写操作请求时,先检查当前事务与数据库元素上的时间戳,
  • 如果请求事务的时间戳大于当前数据元素的时间戳,再检查数据元素上次操作的事务是否提交,如果已经提交,则同意本次写请求;如果未提交,则需要推迟本次请求;
  • 如果事务时间戳小于当前数据元素的时间戳,本次请求事务需要中止;
  1. 当收到事务提交请求时,更新数据元素上的提交状态;同时唤醒等待的事务请求;

  2. 当收到事务T中止请求时,那么回退事务T对应的所有操作数据;等待的事务需要重新发起读或写请求,因为需要检查事务T的写被中止后是否合法。

多版本时间戳

基于时间戳的并发控制调度器,如上面介绍的,会存在读写之间冲突,所以在这个基础上进行了一个重要的演进,就是同时保留数据库元素的多个带不同时间戳的版本,使得读写可以同时进行。

多版本时间戳的流程与上面流程类似:

  1. 当收到写操作请求时WT(X),如果请求被同意,那么X的一个新版本Xi被创建,它的时间戳为Ti(X);
  2. 此时收到一个读操作请求时RU(X)时,最新版本检查不通过时,查找时间戳小于事务U的版本X;也是就WT(X)执行前的版本,就是当前可读的版本,同意RU(X)在版本X上的读请求;
  3. 数据元素的时间戳与对应的版本有关;
  4. 当然再有事务的写请求来时,还是需要在最后的版本Xi上处理;
  5. 旧版本的清理,当X的某个版本上的时间戳小于任何当前活跃事务的时间戳时,就可以清理掉它了。

多版本时间戳的方式,解决了读写并发时的性能问题。

时间戳与封锁

在大多数只读事务或者并发读写同一元素的情况不频繁时,基于时间戳的调度比较有优势;

而当读写并发比较高,而且对同一数据库元素竞争较大时,封锁调度反而比较优,因为此种情况下基于时间戳的调度,需要进行频繁的回退操作。

在现代商用数据库中,会将事务分为只读事务和读写事务,在只读事务时,只使用时间戳的方式,而只读事务时采用两阶段锁的方式。

总结

基于时间戳的调度模型可以说是一种乐观的模型,它假设没有非可串行化行为发生,并且只有在违例发生时才会进行修正或者中止。与此相反,封锁的调度模型是假设非可串行化行为一定会发生,那么提前进行预防,并且推迟可能发生的事务,但不中止它们,它是一种悲观模型。

这两种模型,如果对于大量只读操作时,乐观型好于悲观型调度器。

结尾

非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!

作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/212244.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

好用免费的AI换脸5个工具

在当今社会的发展中,人工智能(Artificial Intelligence, AI)扮演着关键的角色,其应用领域不断扩展。作为AI的一个分支,换脸技术近年来备受欢迎。这项技术使得将一个人的面部特征迁移到另一个人的照片或视频成为可能。除…

SQL面试题,判断if的实战应用

有如下表,请对这张表显示那些学生的成绩为及格,那些为不及格 1、创建表,插入数据 CREATE TABLE chapter8 (id VARCHAR(255) NULL,name VARCHAR(255) NULL,class VARCHAR(255) NULL,score VARCHAR(255) NULL );INSERT INTO chapter8 (id, n…

【C语言快速学习基础篇】之一基础类型、进制转换、数据位宽

文章目录 一、基础类型(根据系统不同占用字节数会有变化)1.1、有符号整形1.2、无符号整形1.3、字符型1.4、浮点型1.5、布尔型 二、进制转换2.1、二进制2.2、八进制2.3、十进制2.4、十六进制2.5、N进制2.6、进制转换关系对应表 三、数据位宽3.1、位3.2、字节3.3、字3.4、双字3.5…

Python Tornado 框架的终极指南!

更多资料获取 📚 个人网站:ipengtao.com Python Tornado框架是一个高性能的异步Web框架,被广泛应用于构建实时Web应用和API服务。本文将深度解析Tornado框架,介绍其核心概念、异步特性、路由系统、模板引擎以及WebSocket支持等方…

spring mvc理解

spring mvc M:model 模型 V:view 视图 C:controller 控制器 S: service 服务处理 D: Dao 数据持久化 视图 我理解就是web页面,帮助用户调用后端接口。 前后端分离之后,view似乎就和后端没什么关系了。 模型 格式…

采样率越高噪声越大?

ADC采样率指的是模拟到数字转换器(ADC)对模拟信号进行采样的速率。在数字信号处理系统中,模拟信号首先通过ADC转换为数字形式,以便计算机或其他数字设备能够处理它们。 ADC采样率通常以每秒采样的次数来表示,单位为赫…

代码随想录算法训练营第四十二天 _ 动态规划_01背包问题、416.分割等和子集。

学习目标: 动态规划五部曲: ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录! 60天训练营打卡计划! 学习内容: 二维数组处理01背包问题 听起来…

画好一张规范的原理图,这些点你可要注意了!

不光是代码有可读性的说法,原理图也有。很多时候原理图不仅仅是给自己看的,也会给其它人看,如果可读性差,会带来一系列沟通问题。所以,要养成良好习惯,做个规范的原理图。此外,一个优秀的原理图…

四、Zookeeper节点类型

目录 1、临时节点 2、永久节点 Znode有两种,分别为临时节点和永久节点。 节点的类型在创建时即被确定,并且不能改变。 1、临时节点 临时节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,

论文阅读——Img2LLM(cvpr2023)

arxiv:[2212.10846] From Images to Textual Prompts: Zero-shot VQA with Frozen Large Language Models (arxiv.org) 一、介绍 使用大语言模解决VQA任务的方法大概两种:multi-modal pretraining and language-mediated VQA,即多模态预训练…

排序:直接选择排序

直接选择排序: 本质: 直接选择排序的本质就是在数组中进行遍历挑选出最大的元素,讲最大的元素放到对应的位置后,再次选出次大的位置,而后又放到对应的位置..........................直到数组成为一个有序序列。 优…

类和对象,this指针

一、类的引入: 如下,在C中,我们可以在结构体中定义函数,如下,之前我们学习C中中一直是在结构体中定义变量。 struct student{void studentinfo(const char* name,const char* gener,int age){ strcpy(_name,name);st…

[b01lers2020]Life on Mars 一个接口的sql schema.schemate表

这里还是很简单的 啥也没有 然后抓包看看 发现传递参数 直接尝试sql 然后如果正确就会返回值 否则 返回1 chryse_planitia union select database(),version() 发现回显 直接开始注入 chryse_planitia union select database(),version()chryse_planitia union select data…

深圳锐杰金融:用金融力量守护社区健康

深圳市锐杰金融投资有限公司,作为中国经济特区的中流砥柱,近年来以其杰出的金融成绩和坚定的社会责任立场引人注目。然而,这并非一个寻常的金融机构。锐杰金融正在用自己的方式诠释企业责任和慈善精神,通过一系列独特的慈善项目&a…

【学习记录】从0开始的Linux学习之旅——字符型设备驱动及应用

一、概述 Linux操作系统通常是基于Linux内核,并结合GNU项目中的工具和应用程序而成。Linux操作系统支持多用户、多任务和多线程,具有强大的网络功能和良好的兼容性。基于前面应用与驱动的开发学习,本文主要讲述如何在linux系统上把应用与驱动…

STC15-串口通信打印输出数据printf函数与sprintf函数

STC15-串口通信打印输出数据printf函数与sprintf函数 1.打印输出数据有二种printf函数与sprintf函数,不同之处有:(1)函数的声明不同(2)函数的功能不同(3)用法举例 该问题引用百度知道…

word模板导出word文件

前期准备工作word模板 右键字段如果无编辑域 ctrlF9 一下&#xff0c;然后再右键 wps 直接 ctrlF9 会变成编辑域 pom.xml所需依赖 <dependencies> <!--word 依赖--> <dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId…

Hadoop入门学习笔记

视频课程地址&#xff1a;https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接&#xff1a;https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 这里写目录标题 一、VMware准备Linux虚拟机1.1. VMware安装Linux虚拟机1.1.1. 修改虚拟机子网IP和网关1.1.2. 安装…

揭秘C语言结构体:通往内存对齐的视觉之旅

揭秘C语言结构体&#xff1a;通往内存对齐的视觉之旅 引言 在C语言的编程旅程中&#xff0c;结构体&#xff08;structs&#xff09;是一个关键而强大的概念。结构体不仅允许我们组织和存储不同类型的数据&#xff0c;而且通过深入了解内存对齐&#xff0c;我们可以更好地优化…

uni-app 微信小程序之自定义中间圆形tabbar

文章目录 1. 自定义tabbar效果2. pages新建tabbar页面3. tabbar 页面结构4. tabbar 页面完整代码 1. 自定义tabbar效果 2. pages新建tabbar页面 首先在 pages.json 文件中&#xff0c;新建一个 tabbar 页面 "pages": [ //pages数组中第一项表示应用启动页&#xff…