当前位置: 首页 > news >正文

网络营销网站功能多语言网站如何开发

网络营销网站功能,多语言网站如何开发,黑龙江建设银行交通违法网站,简约大方自助建站模板文章目录 MySQL事务管理0. MySQL的CURD不加控制#xff0c;出现的问题1. 什么是事务2. 为什么会出现事务3. 事务的版本支持与提交方式3.1 版本支持3.2 提交方式 4. 事务的操作4.0 准备工作4.1 事务正常操作(1) 创建保存点后, rollback(2) 直接rollback(3) 正常提交 4.2 事务异… 文章目录 MySQL事务管理0. MySQL的CURD不加控制出现的问题1. 什么是事务2. 为什么会出现事务3. 事务的版本支持与提交方式3.1 版本支持3.2 提交方式 4. 事务的操作4.0 准备工作4.1 事务正常操作(1) 创建保存点后, rollback(2) 直接rollback(3) 正常提交 4.2 事务异常验证与产出结论(1) 未commit客户端崩溃MySQL自动会回滚(2) commit了客户端崩溃MySQL数据不会在受影响已经持久化(3) 对比试验begin操作会自动更改提交方式不会受MySQL是否自动提交影响(4) 证明单条SQL与事务的关系 5. 事务隔离级别5.1 如何理解隔离性15.2 隔离级别5.3 查看与设置隔离性(1) 查看(2) 设置 5.4 读未提交Read Uncommitted5.5 读提交Read Committed5.4 可重复读Repeatable Read5.5 串行化Serializable5.6 隔离性总结 6. 一致性(Consistency)的理解7. 如何理解隔离性2(提高)7.1 数据库并发的场景7.2 读-写7.3 3个前提知识(1) 3个记录隐藏列字段(2) undo 日志 7.4 模拟MVCC7.5 Read View整体过程 8. RR 与 RC的本质区别8.1 当前读和快照读在RR级别下的区别8.2 RR 与 RC的本质区别 MySQL事务管理 0. MySQL的CURD不加控制出现的问题 CURD需要满足下面的属性 买票的过程必须是原子的买票的过程不能互相影响买完票应该要永久有效买前和买后状态都要是确定的状态即有票还是没票 1. 什么是事务 在现实生活中使用SQL语句时不一定一条语句就能够解决问题我们有时候的操作是需要一批SQL来共同组合才有意义。比如我向你转账100是update 我账户的钱 sub 100update 你账户的钱 add 100这两条SQL单独拿出来在技术上来看就是两条对列操作的语句没有什么意义。但是站在上层即转账和被转账的人来看两条语句和在一起对他们而言就是转账逻辑我们把这两条SQL构成的一组DML语句就叫做事务。 事务的本质一定是要站在MySQL上层(即MySQL的使用者)去看待SQL语句。 事务 事务就是一组DML语句组成这些语句在逻辑上存在相关性这一组DML语句要么全部成功要么全部失败是一个整体。MySQL提供一种机制保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。 正如我们上面所说一个MySQL 数据库可不止你一个事务在运行同一时刻甚至有大量的请求被包装成事务 在向MySQL 服务器发起事务处理请求。而每条事务至少一条SQL 最多很多SQL ,这样如果大家都访问同样的表数据在不加保护的情况就绝对会出现问题。甚至因为事务由多条SQL 构成那么也会存在执行到一半出错或者不想再执行的情况那么已经执行的怎么办呢 所以一个完整的事务绝对不是简单的sql 集合还需要满足如下四个属性 原子性一个事务(transaction)中的所有操作要么全部完成要么全部不完成不会结束在中间某个环节。事务在执行过程中发生错误会被回滚(Rollback)到事务开始前的状态就像这个事务从来没有执行过一样。一致性在事务开始之前和事务结束以后数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。隔离性数据库允许多个并发事务同时对其数据进行读写和修改的能力隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别包括读未提交(Read uncommitted )、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)持久性事务处理结束后对数据的修改就是永久的即便系统故障也不会丢失。 上面四个属性可以简称为ACID。 原子性(Atomicity或称不可分割性)一致性(Consistency)隔离性(Isolation又称独立性)持久性(Durability) 2. 为什么会出现事务 事务被MySQL 编写者设计出来,本质是为了当应用程序访问数据库的时候事务能够简化我们的编程模型不需要我们去考虑各种各样的潜在错误和并发问题。可以想一下当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了服务器宕机了同时更改一个数据怎么办对吧?因此事务本质上是为了应用层服务的。而不是伴随着数据库系统天生就有的。 约定我们后面把MySQL中的一行信息称为一行记录。 3. 事务的版本支持与提交方式 3.1 版本支持 在 MySQL中只有使用了 Innodb 数据库引擎的数据库或表才支持事务 MyISAM 不支持。 查看数据库引擎 mysql show engines \G这里只给出了InnoDB和MyISAM 3.2 提交方式 事务的提交方式常见的有两种自动提交和手动提交 查看事务提交方式 mysql show variables like autocommit;用SET来改变MySQL 的自动提交模式: mysql set autocommit0; # SET AUTOCOMMIT0 禁止自动提交mysql set autocommit1; # SET AUTOCOMMIT1 开启自动提交4. 事务的操作 4.0 准备工作 查看mysql的客户端和服务端。我们使用的是mysql的客户端mysql作为一套网络服务也可以使用远程连接的方式操作即一个mysqld可以被多个客户端访问。 云服务器默认开启3306 mysqld服务 为了便于演示我们将mysql的默认隔离级别设置成读未提交 mysql set global transaction isolation level read uncommitted;需要重启终端进行查看 mysql select tx_isolation;创建测试表 mysql create table if not exists account(- id int primary key,- name varchar(50) not null default ,- blance decimal(10,2) not null default 0.0- )ENGINEInnoDB DEFAULT CHARSETUTF8;在打开两个客户端去连接mysqld # 查看有多少人连接mysql mysql show processlist;4.1 事务正常操作 证明事务的开始与回滚 (1) 创建保存点后, rollback 首先确认当前事务的提交方式是自动提交 开启事务 mysql start transaction; # 开始一个事务begin也可以推荐begin为了方便观察我们在右侧也开启一个事务 向左侧事务添加保存点 mysql savepoint s1; # 创建一个保存点s1在右侧观察表发现没有数据 而后我们在左侧的事务插入数据在右侧就可以观察到 继续重复上面的动作创建一个保存点插入数据后都可以在右边的事务中观察到 但此时我们不想去插入王五了那么我们就可以根据设置的s3保存点向前回滚将王五这条数据撤销 mysql rollback to s3;通过右侧去查看左侧发现王五这条记录已经没有了 同样我们也可以回滚到s2和s1我们直接回滚到s1发现整张表中数据没了 我们不想再操作左侧事务直接结束提交 mysql commit;同样结束提交右侧最终的结果依然是空的因为事务提交时的结果就是没有数据。 (2) 直接rollback 在启动这两个事务如果不设置保存点直接进行rollback那就是将从事务开始到目前的所有操作全都回滚掉。 (3) 正常提交 再启动一次这两个事务并且不回滚直接commit就会发现数据最终保存到了数据库中即便之后rollback也不起作用。 因此我们所提到的回滚操作是在事务运行期间才可以进行回滚事务一旦结束提交就无法回滚。 4.2 事务异常验证与产出结论 (1) 未commit客户端崩溃MySQL自动会回滚 首先明确我们的提交方式仍然是自动提交 我们开启两侧的事务后再插入新的数据 直接使用快捷键ctrl \营造客户端崩溃的场景 后再观察右侧发现新插入的数据消失了实际上就是事务因异常情况从而自动回滚 还是像上面一样插入开启两侧事务插入数据 此时直接将左侧客户端关闭仍然产生回滚现象数据未插入 (2) commit了客户端崩溃MySQL数据不会在受影响已经持久化 还是在刚才的基础上我们重新开启两侧事务commit之后再ctrl \使客户端崩溃 此时我们发现数据没有丢失所以commit的作用是将数据持久化到MySQL中 (3) 对比试验begin操作会自动更改提交方式不会受MySQL是否自动提交影响 先把事务的提交方式设置为手动提交 插入数据没有commit客户端直接崩溃数据还是会丢失 事务提交方式依然是手动这时在崩溃之前commit查看发现事务没有丢失 由此可见mysql的提交方式无论是自动还是手动并不会影响我们事务的手动提交。 (4) 证明单条SQL与事务的关系 我们这里还是手动提交 示例1 在begin之后删除田七的数据并进行commit就将这个删除永久执行了 示例2 我们不在事务中直接进行存粹的SQL操作删除id2的数据后直接看发现是已经删除的 但是一旦当我们的客户端异常崩溃此时在去右侧查看这张表发现2又回来了 示例3 将事务提交方式改成自动 此时也是执行单纯的SQL语句删除id1的数据删除后直接崩溃异常。发现数据就是真正的删除了 对比示例2与示例3 两者是在比较单SQL语句在是否开启事务自动提交下的现象自动提交只对单条SQL有用如果不是自动提交的那么在出现故障时单SQL就会产生回滚使该SQL不影响数据库中的内容如果是自动提交的那么在出现故障时单SQL就会自动提交改变数据库中的内容进行持久化。 因此我们可以再次验证一下单SQL如果在自动提交关闭的情况下进行commit会发生什么情况 我们发现同样永久修改了数据库。 由此可以证明每一条SQL语句就是一个事务只不过以前存在自动提交我们并不能发现。 结论 只要输入begin或者start transaction事务便必须要通过commit提交才会持久化与是否设置set autocommit 无关。事务可以手动回滚同时当操作异常MySQL会自动回滚对于InnoDB 每一条SQL 语言都默认封装成事务自动提交。select有特殊情况因为MySQL 有MVCC 从上面的例子我们能看到事务本身的原子性(回滚)持久性(commit) 事务操作注意事项 如果没有设置保存点也可以回滚只能回滚到事务的开始。直接使用 rollback(前提是事务还没有提交)如果一个事务被提交了commit则不可以回退rollback可以选择回退到哪个保存点InnoDB 支持事务 MyISAM 不支持事务开始事务可以使用start transaction 或者begin 5. 事务隔离级别 5.1 如何理解隔离性1 感性理解 上面是一个时间轴假设你在2000年出生那么你只能看到你出生后的事情无法看到2000年之前的事情有一个1900年出生的人他只活了100岁那么他只能看到从他出生到2000年之间的事情无法看到2000年之后的事情。也就是说一个人只能看到在他生命周期之间发生的事情无法看到以外的事情这就叫做隔离 同样一个事务在执行期间为了防止受到干扰于是引入了隔离性的特征根据影响程度的不同划分出了隔离级别。 理论推导 MySQL服务可能会同时被多个客户端进程(线程)访问访问的方式以事务方式进行一个事务可能由多条SQL构成也就意味着任何一个事务都有执行前执行中执行后的阶段。而所谓的原子性其实就是让用户层要么看到执行前要么看到执行后。执行中出现问题可以随时回滚。所以单个事务对用户表现出来的特性就是原子性。但毕竟所有事务都要有个执行过程那么在多个事务各自执行多个SQL的时候就还是有可能会出现互相影响的情况。比如多个事务同时访问同一张表甚至同一行数据。就如同你妈妈给你说你要么别学要学就学到最好。至于你怎么学中间有什么困难你妈妈不关心。那么你的学习对你妈妈来讲就是原子的。那么你学习过程中很容易受别人干扰此时就需要将你的学习隔离开保证你的学习环境是健康的。数据库中为了保证事务执行过程中尽量不受干扰就有了一个重要特征隔离性数据库中允许事务受不同程度的干扰就有了一种重要特征隔离级别 5.2 隔离级别 读未提交Read Uncommitted 在该隔离级别所有的事务都可以看到其他事务没有提交的执行结果。实际生产中不可能使用这种隔离级别的但是相当于没有任何隔离性也会有很多并发问题如脏读幻读不可重复读等我们上面为了做实验方便用的就是这个隔离性。读提交Read Committed 该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读即一个事务执行时如果多次 select 可能得到不同的结果。可重复读Repeatable Read 这是 MySQL 默认的隔离级别它确保同一个事务在执行中多次读取操作数据时会看到同样的数据行。但是会有幻读问题。串行化Serializable这是事务的最高隔离级别它通过强制事务排序使之不可能相互冲突从而解决了幻读的问题。它在每个读的数据行上面加上共享锁。但是可能会导致超时和锁竞争(这种隔离级别太极端实际生产基本不使用) 隔离级别如何实现隔离基本都是通过锁实现的不同的隔离级别锁的使用是不同的。常见有表锁行锁读锁写锁间隙锁(GAP),Next-Key锁(GAP行锁)等。 5.3 查看与设置隔离性 (1) 查看 查看全局隔离级别 mysql select global.tx_isolation;查看会话(当前)全局隔级别 mysql select session.tx_isolation;默认同上 mysql select tx_isolation;说明 方式3和方式2相同方式3是方式2的缩写形式我们登录一次XShell并且成功连接就叫做一次会话相比于sessionglobal是session的默认配置当我们登陆mysql后默认mysql会读取全局配置好的隔离级别即global的隔离级别用来初始化本次登陆的会话(session)隔离级别。设置session隔离级别并不会影响其他会话设置global隔离级别后续重新登录时其他会话会受到影响 (2) 设置 SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}说明 []内部表示可选项表示选择session还是global的设置。级别有四种同样选择其一即READ UNCOMMITTED 、 READ COMMITTED 、 REPEATABLE READ 、SERIALIZABLE分别代表读未提交、读提交、可重复读、串行化 我们想以会话(session)的方式将事务设置成读提交 mysql set session transaction isolation level read committed;验证其他会话的隔离没有改变 注意一旦修改了global的隔离级别当前会话必须重新登录隔离级别才会被修改 5.4 读未提交Read Uncommitted 在上面4.1 事务的正常操作中我们使用的就是读未提交这里正式说明一下。 首先要把事务global隔离级别设置成读未提交同时保证当前会话的隔离级别是读未提交 后begin开启左右两个事务此时两个事务在并发运行 我们向左侧事务中插入一些数据发现右侧立马就能够看到 可是我们是把在begin和commit之间的操作打成包才叫做一个事务所以左右两侧的事务都不完整。 由于事务具有原子性在左侧事务没有结束(即没有commit)时理论上右侧事务是无法看到左侧未结束的事务但是我们设置了读未提交结果就是在左侧事务执行的过程中右侧事务能够看到左侧事务的一举一动。 同样我们对左侧事务的更新和回滚右侧事务也能够立马看到。 在事务中一个事务未结束并且正在进行CURD操作另一个事务能够立马看到此事务的数据我们把这种现象称为读未提交。就好像多线程中一个线程对共享资源修改另一个线程立马能够看到一定是因为没有加锁。所以对于读未提交这种隔离级别几乎没有加锁虽然效率高但是问题太多严重不建议采用。 读未提交隔离级别的问题 脏读一个事务在执行中读到另一个执行中事务的更新(或其他操作)但是未commit的数据这种现象叫做脏读 (dirty read)。 5.5 读提交Read Committed 首先要把事务global隔离级别设置成读提交同时保证当前会话的隔离级别是读提交。 现在我们开启两个事务使它们并发运行 向左侧事务插入一条数据此时右侧事务去查看并不能看到 此时我们更新左侧数据和上面一样右侧事务并不能看到但是左侧事务自己查看可以看到 一旦我们提交左侧事务即使右侧事务并未提交也能看到左侧事务 在事务中一个事务CURD期间另一个事务不能看到只有当前事务commit提交结束后才能被看到我们把这种现象称为读提交上面例子中一个事务commit结束后另一个事务在没有commit时就能看到当前结果在前后用select查询结果时出现了不同的结果另一个事务在未提交时还是受到了当前事务的影响 读未提交隔离级别的问题 不可重复读此时还在当前事务中并未commit那么就造成了同一个事务内同样的读取在不同的时间段(依旧还在事务操作中)读取到了不同的值这种现象叫做不可重复读(non reapeatable read) 问题 不可重复读真的是问题吗 我们构建下面的场景在一家公司里老板会根据员工的薪资来发放奖品。 老板把任务交给小张小张开启一个事务准备查询。现有一名叫做tom的员工告诉老板自己今年贡献要求老板涨薪老板同意把他的薪资由3200变4500同时把此任务交给小王让小王去修改数据库tom的薪资于是小王也开启了一个事务。小张像上面一样一条一条查询查询到3000~4000之间时小王还未修改tom薪资于是在这个区间内就查询到了tom因为两个事务在并发运行此条语句结束后小王突然修改了tom的薪资小张去下一个区间查询也找到了tom整个查询完后把数据交给发奖的人他们一看发现tom的名字竟然出现了2次难道tom有两种薪资要给tom发两个奖品吗这种情况不合理。 由此可见不可重复读是存在问题的。 5.4 可重复读Repeatable Read 首先要把事务global隔离级别设置成可重复读同时保证当前会话的隔离级别是可重复读 开启两个事务并发运行。 对左侧的事务插入更新和删除后commit提交左侧事务右侧事务没有提交右侧事务去查看是看不到的 右侧事务无论什么时候进行查找看到的结果都是一致的这叫做可重复读 只有右侧事务commit提交结束后才能看到左侧事务 在事务中一个事务CURD后coomit提交另一个事务也commit提交后才能看到结果我们把这种现象称为可重复读 可重复读隔离级别的问题 幻读专门针对insert。 多次查看发现左侧在对应事务中insert的数据在右侧的事务周期中也没有什么影响也符合可重复的特点但是一般的数据库在可重复读情况的时候无法屏蔽其他事务insert的数据(为什么因为隔离性实现是对数据加锁完成的而insert待插入的数据因为并不存在那么一般加锁无法屏蔽这类问题),会造成虽然大部分内容是可重复读的但是insert的数据在可重复读情况被读取出来导致多次查找时会多查找出来新的记录就如同产生了幻觉。这种现象叫做幻读(phantom read)。很明显MySQL在RR级别的时候是解决了幻读问题的(解决的方式是用Next-Key锁(GAP行锁))解决的。 5.5 串行化Serializable 首先要把事务global隔离级别设置成串行化同时保证当前会话的隔离级别是串行化。 左右两侧开启两个事务如果两个事务对表的操作都是读操作那么这两个事务可以并发执行不会阻塞 如表中有任何一个事务对表进行写操作那么这个事务会立即被阻塞 直到访问这张表的其他事务都提交后这个阻塞事务才会被唤醒才能对表进行修改操作 串行化对所有操作全部加锁进行串行化不会有问题但是只要串行化效率很低几乎完全不会被采用 两个事务同时读取不会串行化共享锁一旦一个事务对表进行CURD操作时此事务会被放入等待队列被阻塞直到另一个事务提交如果此事务阻塞时间过长将会由于锁等待超时退出当前事务。 5.6 隔离性总结 其中隔离级别越严格安全性越高但数据库的并发性能也就越低往往需要在两者之间找一个平衡点不可重复读的重点是修改和删除同样的条件, 你读取过的数据,再次读取出来发现值不一样了幻读的重点在于新增同样的条件, 第1次和第2次读出来的记录数不一样。mysql 默认的隔离级别是可重复读,一般情况下不要修改上面的例子可以看出事务也有长短事务这样的概念。事务间互相影响指的是事务在并行执行的时候即都没有commit的时候影响会比较大。 6. 一致性(Consistency)的理解 事务执行的结果必须使数据库从一个一致性状态变到另一个一致性状态。当数据库只包含事务成功提交的结果时数据库处于一致性状态。 一个事务中所有操作要么全部完成要么全部不完成不会结束在中间某个环节。事务在执行过程中发生错误会被回滚到事务开始前的状态就像这个事务从来没有执行过一样即一致性需要原子性来保证 数据库允许多个并发事务同时对其数据进行读写和修改的能力不会因为多个事务并发执行时由于交叉执行而导致数据的不一致即一致性需要隔离性来保证 事务处理结束后对数据的修改就是永久的即便系统故障也不会丢失即一致性需要持久性来保证 其实一致性和用户的业务逻辑强相关一般MySQL提供技术支持但是一致性还是要用户业务逻辑做支撑也就是一致性是由用户决定的。而技术上通过AID保证C 总结一致性是数据库最终想要达成的效果它不仅需要原子性隔离性持久性来保证还需要用户业务逻辑做支撑。 7. 如何理解隔离性2(提高) 上面的学习中我们已经能够很容易理解读未提交和串行化那么关于读提交(RC)和可重复读(RR)是怎么做到的呢它们的原理是什么在RR级别中多个事务的update多个事务的insert,多个事务的delete是否会有加锁现象呢下面就来深入理解一下这部分内容。 7.1 数据库并发的场景 读-读不存在任何问题也不需要并发控制读-写有线程安全问题可能会造成事务隔离性问题可能遇到脏读幻读不可重复读写-写有线程安全问题可能会存在更新丢失问题比如第一类更新丢失第二类更新丢失 7.2 读-写 多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制 1.事务的先后顺序问题如何保证 MySQL会为事务分配单向增长的事务ID为每个修改保存一个版本版本与事务ID关联。因此每个事务都要有自己的事务ID可以根据事务ID的大小来决定事务到来的先后顺序 2.mysqld可能会面临多个事务的情况 事务会有自己的执行过程即事务会有自己的生命周期mysqld要对多个事务进行管理如何管理先描述再组织。所以事务在我们看来在mysqld中一定是对应一个或一套结构体对象或类对象即事务要有自己的结构体这些结构体需要被相应的数据结构管理起来那么对事务的操作就变成了对相应数据结构的增删查改 7.3 3个前提知识 理解MVCC 需要知道三个前提知识 3个记录隐藏字段undo 日志Read View (1) 3个记录隐藏列字段 DB_TRX_ID 6 byte最近修改( 修改/插入)事务ID记录创建这条记录/最后一次修改该记录的事务IDDB_ROLL_PTR : 7 byte回滚指针指向这条记录的上一个版本简单理解成指向历史版本就行这些数据一般在undo log 中DB_ROW_ID : 6 byte隐含的自增ID隐藏主键如果数据表没有主键 InnoDB 会自动以DB_ROW_ID 产生一个聚簇索引补充实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除而是删除flag变了 示例我们创建一个学生表向其中插入数据我们查看表是只有name和age两列 实际上还会添加3个隐藏字段 我们目前并不知道创建该记录的事务ID隐式主键我们就默认设置成91。第一条记录也没有其他版本我们设置回滚指针为null。 (2) undo 日志 MySQL 将来是以服务进程的方式在内存中运行。我们之前所讲的所有机制索引事务隔离性日志等都是在内存中完成的即在MySQL 内部的相关缓冲区中保存相关数据完成各种判断操作。然后在合适的时候将相关数据刷新到磁盘当中的。 所以我们这里理解undo log简单理解成就是MySQL 中的一段内存缓冲区用来保存日志数据的就行。 7.4 模拟MVCC 现在有一个事务10(仅仅为了好区分)对student表中记录进行修改(update)将name(张三)改成name(李四) 事务10,因为要修改所以要先给该记录加行锁。修改前先将改行记录拷贝到undo log中所以undo log中就有了一行副本数据。(原理就是写时拷贝)所以现在MySQL 中有两行同样的记录。现在修改原始记录中的name改成 ‘李四’。并且修改原始记录的隐藏字段DB_TRX_ID 为当前事务10 的ID, 我们默认从10 开始之后递增。而原始记录的回滚指针DB_ROLL_PTR 列里面写入undo log中副本数据的地址从而指向副本记录既表示我的上一个版本就是它。事务10提交释放锁 备注此时最新的记录是’李四‘那条记录 现在又有一个事务11对student表中记录进行修改(update)将age(28)改成age(38)。 事务11,因为也要修改所以要先给该记录加行锁。该记录是那条修改前现将改行记录拷贝到undo log中所以undo log中就又有了一行副本数据。此时新的副本我们采用头插方式插入undo log。现在修改原始记录中的age改成 38。并且修改原始记录的隐藏字段DB_TRX_ID 为当前事务11 的ID。而原始记录的回滚指针DB_ROLL_PTR 列里面写入undo log中副本数据的地址从而指向副本记录既表示我的上一个版本就是它。事务11提交释放锁。 这样我们就有了一个基于链表记录的历史版本链。所谓的回滚无非就是用历史数据覆盖当前数据。 上面的一个一个版本我们可以称之为一个一个的快照。 上面是以更新upadte主讲的下面我们就来谈论insertdelete和select insert和delete delete: 记录被删除并不代表真的删除而是先将记录拷贝一份放到undo log中设置删除flag为1这样回滚操作时falg又变回0删除的数据就会恢复。 insert: 因为insert是插入也就是之前没有数据那么insert也就没有历史版本。但是一般为了回滚操作insert的数据也是要被放入undo log中如果当前事务commit了那么这个undolog 的历史insert记录就可以被清空了。 即insert和delete也能形成版本。 select 首先select不会对数据做任何修改所以为select维护多版本没有意义。不过此时有个问题就是 select读取是读取最新的版本呢还是读取历史版本 当前读读取最新的记录就是当前读。增删改都叫做当前读select也有可能当前读比如select lock in share mode(共享锁), select for update快照读读取历史版本(一般而言)就叫做快照读 在多个事务同时删改查的时候都是当前读是要加锁的。那同时有select过来如果也要读取最新版(当前读)那么也就需要加锁这就是串行化。 但如果是快照读读取历史版本的话是不受加锁限制的。也就是可以并行执行换言之提高了效率即MVCC的意义所在。 隔离级别决定了select查询时应该进行当前读还是快照读。 回到我们开始的问题为什么要有隔离级别呢 事务从begin-CURD-commit是有一个阶段的。也就是事务有执行前执行中执行后的阶段。但不管怎么启动多个事务总是有先有后的。那么多个事务在执行中CURD操作是会交织在一起的。那么为了保证事务的“有先有后”是不是应该让不同的事务看到它该看到的内容这就是所谓的隔离性与隔离级别要解决的问题 7.5 Read View Read View就是事务进行快照读操作的时候生产的读视图(Read View)在该事务执行的快照读的那一刻会生成数据库系统当前的一个快照记录并维护系统当前活跃事务的ID(当每个事务开启时都会被分配一个ID, 这个ID是递增的所以最新的事务ID值越大)Read View 在MySQL 源码中,就是一个类本质是用来进行可见性判断的。 即当我们某个事务执行快照读的时候对该记录创建一个Read View 读视图把它比作条件,用来判断当前事务能够看到哪个版本的数据既可能是当前最新的数据也有可能是该行记录的undo log 里面的某个版本的数据。 即Read View 是事务可见性的一个类不是事务创建出来就会有Read View 而是当这个事务(已经存在)首次进行快照读的时候mysql形成Read View 下面我们简化Read View结构 class ReadView {// 省略... private:/** 高水位大于等于这个ID的事务均不可见*/trx_id_t m_low_limit_id;/** 低水位小于这个ID的事务均可见 */trx_id_t m_up_limit_id;/** 创建该 Read View 的事务ID*/trx_id_t m_creator_trx_id;/** 创建视图时的活跃事务id列表*/ids_t m_ids;/** 配合purge标识该视图不需要小于m_low_limit_no的UNDO LOG* 如果其他视图也不需要则可以删除小于m_low_limit_no的UNDO LOG*/trx_id_t m_low_limit_no;/** 标记视图是否被关闭*/bool m_closed;// 省略... };成员说明 m_ids一张列表用来维护Read View生成时刻系统正活跃的事务IDup_limit_id记录m_ids列表中事务ID最小的IDlow_limit_idReadView生成时刻系统尚未分配的下一个事务ID也就是目前已出现过的事务ID的最大值1creator_trx_id创建该ReadView的事务ID 我们在实际读取数据版本链的时候是能读取到每一个版本对应的事务ID的即当前记录的DB_TRX_ID。 我们现在得到了当前快照读的ReadView 和 版本链中的某一个记录的DB_TRX_ID。 问题当前快照读应不应该读到当前版本记录呢 事务ID小于up_limit_id的事务一定是生成Read View时已经提交的事务因为up_limit_id是生成Read View时刻系统中活跃事务ID中的最小ID因此事务ID比它小的事务在生成Read View时一定已经提交了。事务ID大于等于low_limit_id的事务一定是生成Read View时还没有启动的事务因为low_limit_id是生成Read View时刻系统尚未分配的下一个事务ID。事务ID位于up_limit_id和low_limit_id之间的事务在生成Read View时可能正处于活跃状态也可能已经提交了这时需要通过判断事务ID是否存在于m_ids中来判断该事务是否已经提交 结论一个事务在进行读操作时只应该看到自己或已经提交的事务所作的修改因此我们可以根据Read View来判断当前事务能否看到另一个事务所作的修改 源码策略如下 如果查到不应该看到当前版本接下来就是遍历下一个版本直到符合条件即可以看到。上面的readview 是当你进行select的时候会自动形成。 整体过程 假设当前有条记录 事务操作 事务4修改name(张三) 变成name(李四) 当事务2 对某行数据执行了快照读数据库为该行数据生成一个Read View 读视图 //事务2的 Read Viewm_ids; // 1,3 up_limit_id; // 1 low_limit_id; // 4 1 5原因ReadView生成时刻系统尚未分配的下一个事务ID creator_trx_id // 2此时版本链是 只有事务4修改过该行记录并在事务2执行快照读前就提交了事务。 我们的事务2在快照读该行记录的时候就会拿该行记录的DB_TRX_ID 去跟up_limit_id,low_limit_id和活跃事务ID列表(trx_list) 进行比较判断当前事务2能看到该记录的版本。 //事务2的 Read View m_ids; // 1,3 up_limit_id; // 1 low_limit_id; // 4 1 5原因ReadView生成时刻系统尚未分配的下一个事务ID creator_trx_id // 2//事务4提交的记录对应的事务ID DB_TRX_ID4//比较步骤 DB_TRX_ID4 up_limit_id1 ? 不小于下一步 DB_TRX_ID4 low_limit_id(5) ? 不大于下一步 m_ids.contains(DB_TRX_ID) ? 不包含说明事务4不在当前的活跃事务中。//结论 故事务4的更改应该看到。 所以事务2能读到的最新数据记录是事务4所提交的版本而事务4提交的版本也是全局角度上最新的版本8. RR 与 RC的本质区别 8.1 当前读和快照读在RR级别下的区别 演示1 启动两个终端将事务的隔离级别都改为可重复读。在两个终端各自启动一个事务在左终端中的事务操作之前先让右终端中的事务查看一下表中的信息。如下 左终端中的事务对表中的信息进行修改并提交针对可重复读的隔离级别右终端中的事务看不到修改后的数据即便左侧commit在右侧的事务只要未停止那么右终端中的事务就看不到修改后的数据因为这种读都被称之为快照读。如下 在右终端中使用select ... lock in share mode命令进行当前读可以看到表中的数据确实是被修改了只是右终端中的事务看不到而已。如下 演示2 我们将左右两侧事务begin以后不让右侧进行快照读仅仅只是让左侧的事务进行修改数据并提交提交之后右侧的事务在进行快照读与当前读我们发现这两个结果是一样的都是当前读的数据 上面两次实验的唯一区别在于右终端中的事务在左终端中的事务修改数据之前是否进行过快照读。事务中快照读的结果是非常依赖该事务首次出现快照读的地方即某个事务中首次出现快照读决定该事务后续快照读结果的能力 8.2 RR 与 RC的本质区别 正是Read View生成时机的不同从而造成RC,RR级别下快照读的结果的不同在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View, 将当前系统活跃的其他事务记录起来。此后在调用快照读的时候还是使用的是同一个Read View所以只要当前事务在其他事务提交更新之前使用过快照读那么之后的快照读使用的都是同一个Read View所以对之后的修改不可见即RR级别下快照读生成Read View时Read View会记录此时所有其他活动事务的快照这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见而在RC级别下的事务中每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因总之在RC隔离级别下是每个快照读都会生成并获取最新的Read View而在RR隔离级别下则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View。正是RC每次快照读都会形成Read View所以RC才会有不可重复读问题
http://www.zqtcl.cn/news/583245/

相关文章:

  • 做网站服务公司王业美
  • 遵义网站建设推广城乡住房建设部官网查询
  • 电商设计网站素材免费建站网站seo
  • 做雕塑网站丹阳网站推广
  • 夏津网站建设公司应用分析网站
  • 长春seo网站优化个人网站要有什么
  • 网站开发流程步骤 口袋青海个人旅游网站建设
  • php企业网站多少钱图书馆网站建设建议
  • 企业网站建设综合实训学习体会个人网站空间申请
  • 企业小型网站要多少钱合肥城乡建设网站首页
  • 济南建站公司注意事项做钓鱼网站要什么工具
  • 网站建设数据录入创建网络公司
  • 行业网站建设报价摄影标志logo设计欣赏
  • 做reference的网站网站首页 模板
  • 微信php网站开发流程图做网站优化好的网络公司
  • 网站显示百度地图长沙制作网页的基本步骤
  • 免费做封面的网站哈尔滨网页制作要多少钱
  • html免费网页素材网站优化教程
  • 百度关键词网站排名优化软件seo服务 收费
  • 中英文切换网站网站建设的关键问题
  • 5款免费网站管理系统wordpress 本地
  • 企业网站制作公司盈利百度云搜索
  • 微云影视自助建站系统大理州建设局网站门户网
  • 构建网站需要会什么意思辽宁省朝阳网站建设
  • 网站建设捌金手指专业1公司域名邮箱注册
  • 建设工程协会网站建设工程合同属于专属管辖吗
  • 网站建设费可分摊几年电子商务网站建设基础
  • wordpress api 发贴北京网站优化seo
  • 青岛网站制作服务商wordpress红包
  • 网站响应式设计如何提高网站文章收录