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

上海网站建设的价格低重庆网站建设推荐

上海网站建设的价格低,重庆网站建设推荐,网站建设管理招聘,网站开发人员 平均工资目录 事物 首先我们来看一个简单的问题 什么是事务 为什么会出现事务 事务的版本支持 事务提交方式 事务常见操作方式 设置隔离级别 事物操作 事物结论 事务隔离级别 理解隔离性 隔离级别 查看与设置隔离性 注意可重复读【Repeatable Read】的可能问题#xff…目录 事物 首先我们来看一个简单的问题 什么是事务 为什么会出现事务 事务的版本支持 事务提交方式 事务常见操作方式 设置隔离级别 事物操作 事物结论 事务隔离级别 理解隔离性 隔离级别 查看与设置隔离性 注意可重复读【Repeatable Read】的可能问题幻读 总结 一致性(Consistency)  理解隔离性 数据库并发的场景有三种 读-写 MVCC Read View RR 与 RC的本质区别 当前读和快照读在RR级别下的区别 RR 与 RC的本质区别RR可重复读RC读提交 事物 首先我们来看一个简单的问题 CURD满足什么属性能解决上述问题 1. 买票的过程得是原子的吧 2. 买票互相应该不能影响吧 3. 买完票应该要永久有效吧 4. 买前和买后都要是确定的状态吧 什么是事务 事务就是一组DML 语句组成这些语句在逻辑上存在相关性这一组 DML 语句要么全部成功要么全部失败是一个整体。MySQL 提供一种机制保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。 事务就是要做的或所做的事情主要用于处理操作量大复杂度高的数据。假设一种场景你毕业了学校的教务系统后台 MySQL 中不在需要你的数据要删除你的所有信息 ( 一般不会 :) ), 那么要删除你的基本信息( 姓名电话籍贯等 ) 的同时也删除和你有关的其他信息比如你的各科成绩你在校表现甚至你在论坛发过的文章等。这样就需要多条 MySQL 语句构成那么所有这些操作合起来就构成了一个事务。 正如我们上面所说一个 MySQL 数据库可不止你一个事务在运行同一时刻甚至有大量的请求被包装成事务在向 MySQL 服务器发起事务处理请求。而每条事务至少一条 SQL 最多很多 SQL , 这样如果大家都访问同样的表数据在不加保护的情况就绝对会出现问题。甚至因为事务由多条 SQL 构成那么也会存在执行到一半出错或者不想再执行的情况那么已经执行的怎么办呢 所以一个完整的事务绝对不是简单的 sql 集合还需要满足如下四个属性 原子性 一个事务 transaction 中的所有操作要么全部完成要么全部不完成不会结束在中间某个环节。事务在执行过程中发生错误会被回滚Rollback 到事务开始前的状态就像这个事务从来没有执行过一样。 一致性 在事务开始之前和事务结束以后数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 隔离性 数据库允许多个并发事务同时对其数据进行读写和修改的能力隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别包括读未提交 Readuncommitted 、读提交 read committed 、可重复读 repeatable read 和串行化 Serializable 持久性 事务处理结束后对数据的修改就是永久的即便系统故障也不会丢失。 上面四个属性可以简称为 ACID 。 原子性 A tomicity 或称不可分割性 一致性 C onsistency 隔离性 I solation 又称独立性 持久性 D urability 。 为什么会出现事务 事务被 MySQL 编写者设计出来 , 本质是为了当应用程序访问数据库的时候 , 事务能够简化我们的编程模型 ,不需要我们去考虑各种各样的潜在错误和并发问题. 可以想一下当我们使用事务时 , 要么提交 , 要么回滚 , 我们不会去考虑网络异常了, 服务器宕机了 , 同时更改一个数据怎么办对吧 ? 因此事务本质上是为了应用层服 务的 . 而不是伴随着数据库系统天生就有的。 PS我们后面把 MySQL 中的一行信息称为一行记录 事务的版本支持 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务 MyISAM 不支持。 mysql show engines; -- 表格显示 mysql show engines \G -- 行显示 *************************** 1 . row *************************** Engine: InnoDB -- 引擎名称 Support: DEFAULT -- 默认引擎 Comment: Supports transactions, row-level locking, and foreign keys -- 描述 Transactions: YES -- 支持事务 XA: YES Savepoints: YES -- 支持事务保存点 *************************** 2 . row *************************** Engine: MRG_MYISAM Support: YES Comment: Collection of identical MyISAM tables Transactions: NO XA: NO Savepoints: NO *************************** 3 . row *************************** Engine: MEMORY -- 内存引擎 Support: YES Comment: Hash based, stored in memory, useful for temporary tables Transactions: NO XA: NO Savepoints: NO *************************** 4 . row *************************** Engine: BLACKHOLE Support: YES Comment: /dev/null storage engine (anything you write to it disappears) Transactions: NO XA: NO Savepoints: NO *************************** 5 . row *************************** Engine: MyISAM Support: YES Comment: MyISAM storage engine Transactions: NO -- MyISAM 不支持事务 XA: NO Savepoints: NO *************************** 6 . row *************************** Engine: CSV Support: YES Comment: CSV storage engine Transactions: NO XA: NO Savepoints: NO *************************** 7 . row *************************** Engine: ARCHIVE Support: YES Comment: Archive storage engine Transactions: NO XA: NO Savepoints: NO *************************** 8 . row *************************** Engine: PERFORMANCE_SCHEMA Support: YES Comment: Performance Schema Transactions: NO XA: NO Savepoints: NO *************************** 9 . row *************************** Engine: FEDERATED Support: NO Comment: Federated MySQL storage engine Transactions: NULL XA: NULL Savepoints: NULL 9 rows in set ( 0.00 sec 事务提交方式 事务的提交方式常见的有两种 自动提交 手动提交 查看事务提交方式 mysql show variables like autocommit; ---------------------- | Variable_name | Value | ---------------------- | autocommit | ON | ---------------------- 1 row in set ( 0.41 sec)         用 SET 来改变 MySQL 的自动提交模式: mysql SET AUTOCOMMIT 0 ; #SET AUTOCOMMIT0 禁止自动提交 Query OK, 0 rows affected ( 0.00 sec) mysql show variables like autocommit ; ---------------------- | Variable_name | Value | ---------------------- | autocommit | OFF | ---------------------- 1 row in set ( 0.00 sec) mysql SET AUTOCOMMIT 1 ; #SET AUTOCOMMIT1 开启自动提交 Query OK, 0 rows affected ( 0.00 sec) mysql show variables like autocommit ; ---------------------- | Variable_name | Value | ---------------------- | autocommit | ON | ---------------------- 1 row in set ( 0.01 sec) 事务常见操作方式 设置隔离级别 mysql set global transaction isolation level READ UNCOMMITTED; Query OK, 0 rows affected (0.00 sec) mysql quit Bye ## 需要重启终端进行查看 mysql select tx_isolation; ------------------ | tx_isolation | ------------------ | READ-UNCOMMITTED | ------------------ 1 row in set , 1 warning (0.00 sec) 事物操作 mysql show variables like autocommit ; -- 查看事务是否自动提交。我们故意设置成自 动提交看看该选项是否影响 begin ---------------------- | Variable_name | Value | ---------------------- | autocommit | ON | ---------------------- 1 row in set ( 0.00 sec) mysql start transaction; -- 开始一个事务 begin 也可以推荐 begin Query OK, 0 rows affected ( 0.00 sec) mysql savepoint save1; -- 创建一个保存点 save1 Query OK, 0 rows affected ( 0.00 sec) mysql insert into account values ( 1 , 张三 , 100 ); -- 插入一条记录 Query OK, 1 row affected ( 0.05 sec) mysql savepoint save2; -- 创建一个保存点 save2 Query OK, 0 rows affected ( 0.01 sec) mysql insert into account values ( 2 , 李四 , 10000 ); -- 在插入一条记录 Query OK, 1 row affected ( 0.00 sec) mysql select * from account; -- 两条记录都在了 ---------------------- | id | name | blance | ---------------------- | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | ---------------------- 2 rows in set ( 0.00 sec) mysql rollback to save2; -- 回滚到保存点 save2 Query OK, 0 rows affected ( 0.03 sec) mysql select * from account; -- 一条记录没有了 -------------------- | id | name | blance | -------------------- | 1 | 张三 | 100.00 | -------------------- 1 row in set ( 0.00 sec) mysql rollback; -- 直接 rollback 回滚在最开始 Query OK, 0 rows affected ( 0.00 sec) mysql select * from account; -- 所有刚刚的记录没有了 Empty set ( 0.00 sec) 事物结论 只要输入begin或者start transaction事务便必须要通过commit提交才会持久化与是否设置set autocommit无关。 事务可以手动回滚同时当操作异常MySQL会自动回滚。对于 InnoDB 每一条 SQL 语言都默认封装成事务自动提交。select有特殊情况因为MySQL 有 MVCC 从上面的例子我们能看到事务本身的原子性(回滚)持久性(commit) 那么隔离性一致性 事务操作注意事项 如果没有设置保存点也可以回滚只能回滚到事务的开始。直接使用 rollback前提是事务还没有提交。如果一个事务被提交了commit则不可以回退rollback。可以选择回退到哪个保存点。InnoDB 支持事务 MyISAM 不支持事务 开始事务可以使 start transaction 或者 begin 事务隔离级别 理解隔离性 MySQL服务可能会同时被多个客户端进程(线程)访问访问的方式以事务方式进行。一个事务可能由多条SQL构成也就意味着任何一个事务都有执行前执行中执行后的阶段。而所谓的原子性其实就是让用户层要么看到执行前要么看到执行后。执行中出现问题可以随时回滚。所以单个事务对用户表现出来的特性就是原子性。 但毕竟所有事务都要有个执行过程那么在多个事务各自执行多个SQL的时候就还是有可能会出现互相影响的情况。比如多个事务同时访问同一张表甚至同一行数据。 就如同你妈妈给你说你要么别学要学就学到最好。至于你怎么学中间有什么困难你妈妈不关心。那么你的学习对你妈妈来讲就是原子的。那么你学习过程中很容易受别人干扰此时就需要将你的学习隔离开保证你的学习环境是健康的。 数据库中为了保证事务执行过程中尽量不受干扰就有了一个重要特征隔离性。数据库中允许事务受不同程度的干扰就有了一种重要特征隔离级别。 隔离级别 读未提交【 Read Uncommitted 】 在该隔离级别所有的事务都可以看到其他事务没有提交的执行结果。实际生产中不可能使用这种隔离级别的但是相当于没有任何隔离性也会有很多并发问题如脏读幻读不可重复读等我们上面为了做实验方便用的就是这个隔离性。 PS一个事物没有commit 但是另一个事物可以里面读到修改这就是脏读问题 读提交【 Read Committed 】 该隔离级别是大多数数据库的默认的隔离级别不是 MySQL 默认的。它满足了隔离的简单定义: 一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读即一个事务执行时如果多次 select 可能得到不同的结果。 PS就是一个事物在未commit之前另一个事物无法看到其修改避免脏读 下面右边这种现象就叫做 读提交 这是一个问题不可重复读。 可重复读【 Repeatable Read 】 这是 MySQL 默认的隔离级别它确保同一个事务在执行中多次读取操作数据时会看到同样的数据行。但是会有幻读问题。 PS解决了 不可重复读问题 即可重复读注意右边也是在begin里面此时左边是commit如果右边commit之后再去select就可以看到左边commit的数据 关于幻读 在其他的数据库中insert的时候可能会存在幻读问题  串行化【 Serializable 】 : 这是事务的最高隔离级别它通过强制事务排序使之不可能相互冲突从而解决了幻读的问题。它在每个读的数据行上面加上共享锁。但是可能会导致超时和锁竞争这种隔离级别太极端实际生产基本不使用 PS在串行化下多个事物可以同时读但是如果 要修改就只能当只有一个事物去访问的时候才可以其他事物要commit 隔离级别如何实现隔离基本都是通过锁实现的不同的隔离级别锁的使用是不同的。常见有表锁行锁读锁写锁间隙锁(GAP),Next-Key 锁 (GAP 行锁 ) 等。不过我们目前现有这个认识就行先关注上层使用。 查看与设置隔离性 -- 查看 mysql SELECT global .tx_isolation ; -- 查看全局隔级别 ----------------------- | global .tx_isolation | ----------------------- | REPEATABLE-READ | ----------------------- 1 row in set , 1 warning ( 0.00 sec) mysql SELECT session .tx_isolation ; -- 查看会话 ( 当前 ) 全局隔级别 ------------------------ | session .tx_isolation | ------------------------ | REPEATABLE-READ | ------------------------ 1 row in set , 1 warning ( 0.00 sec) mysql SELECT tx_isolation; -- 默认同上 ----------------- | tx_isolation | ----------------- | REPEATABLE-READ | ----------------- 1 row in set , 1 warning ( 0.00 sec) --设置 -- 设置当前会话 or 全局隔离级别语法 SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE} -- 设置当前会话隔离性另起一个会话看不多只影响当前会话 mysql set session transaction isolation level serializable; -- 串行化 Query OK, 0 rows affected ( 0.00 sec) mysql SELECT global .tx_isolation ; -- 全局隔离性还是 RR ----------------------- | global .tx_isolation | ----------------------- | REPEATABLE-READ | ----------------------- 1 row in set , 1 warning ( 0.00 sec) mysql SELECT session .tx_isolation ; -- 会话隔离性成为串行化 ------------------------ | session .tx_isolation | ------------------------ | SERIALIZABLE | ------------------------ 1 row in set , 1 warning ( 0.00 sec) mysql SELECT tx_isolation; -- 同上 ---------------- | tx_isolation | ---------------- | SERIALIZABLE | ---------------- 1 row in set , 1 warning ( 0.00 sec) -- 设置全局隔离性另起一个会话会被影响 mysql set global transaction isolation level READ UNCOMMITTED; Query OK, 0 rows affected ( 0.00 sec) mysql SELECT global .tx_isolation ; ----------------------- | global .tx_isolation | ----------------------- | READ-UNCOMMITTED | ----------------------- 1 row in set , 1 warning ( 0.00 sec) mysql SELECT session .tx_isolation ; ------------------------ | session .tx_isolation | ------------------------ | READ-UNCOMMITTED | ------------------------ 1 row in set , 1 warning ( 0.00 sec) mysql SELECT tx_isolation; ------------------ | tx_isolation | ------------------ | READ-UNCOMMITTED | ------------------ 1 row in set , 1 warning ( 0.00 sec) -- 注意如果没有现象关闭 mysql 客户端重新连接。 注意可重复读【Repeatable Read】的可能问题幻读 mysql select * from account; -- 多次查看发现终端 A 在对应事务中 insert 的数据在终端 B 的事务周期中也没有什么影响也符合可重复的特点。但是一般的数据库在可重复读情况的时候无法屏蔽其他事务insert 的数据 ( 为什么因为隔离性实现是对数据加锁完成的而 insert 待插入的数据因为并不存在那么一般加锁无法屏蔽这类问题), 会造成虽然大部分内容是可重复读的但是 insert 的数据在可重复读情况被读取出来导致多次查找时会多查找出来新的记录就如同产生了幻觉。这种现象叫做幻读(phantom read)。很明显 MySQL 在 RR 级别的时候是解决了幻读问题的 ( 解决的方式是用 Next-Key 锁(GAP行锁 ) 解决的。这块比较难有兴趣同学了解一下 ) 。 总结 其中隔离级别越严格安全性越高但数据库的并发性能也就越低往往需要在两者之间找一个平衡点。 不可重复读的重点是修改和删除同样的条件, 你读取过的数据,再次读取出来发现值不一样了。幻读的重点在于新增同样的条件, 第1次和第2次读出来的记录数不一样 说明 mysql 默认的隔离级别是可重复读,一般情况下不要修改。上面的例子可以看出事务也有长短事务这样的概念。事务间互相影响指的是事务在并行执行的时候即都没有commit的时候影响会比较大。 一致性(Consistency)  事务执行的结果必须使数据库从一个一致性状态变到另一个一致性状态。当数据库只包含事务成功提交的结果时数据库处于一致性状态。如果系统运行发生中断某个事务尚未完成而被迫中断而改未完成的事务对数据库所做的修改已被写入数据库此时数据库就处于一种不正确不一致的状态。因此一致性是通过原子性来保证的。 其实一致性和用户的业务逻辑强相关一般MySQL提供技术支持但是一致性还是要用户业务逻辑做支撑也就是一致性是由用户决定的。而技术上通过AID保证C。 理解隔离性 数据库并发的场景有三种 读 - 读 不存在任何问题也不需要并发控制 读 - 写 有线程安全问题可能会造成事务隔离性问题可能遇到脏读幻读不可重复读此情况为主要所以我们就讨论这个 写 - 写 有线程安全问题可能会存在更新丢失问题比如第一类更新丢失第二类更新丢失 读-写 MVCC 多版本并发控制 MVCC 是一种用来解决 读- 写 冲突 的 无锁并发控制。 为事务分配单向增长的事务 ID 为每个修改保存一个版本版本与事务 ID 关联读操作只读该事务开始前的数据库的快照。 所以 MVCC 可以为数据库解决以下问题。 在并发读写数据库时可以做到在读操作时不用阻塞写操作写操作也不用阻塞读操作提高了数据库并发读写的性能。同时还可以解决脏读幻读不可重复读等事务隔离问题但不能解决更新丢失问题。 理解 MVCC 需要知道三个前提知识 3 个记录隐藏字段 undo 日志 Read View undolog本质是在事物没有提交commit之前使用的 回滚的本质就是拿着undolog历史数据中的版本链中的数据去覆盖现在的数据注意图的话实际上是那么做的现在这么说其实是好理解uodolog里面有两种日志一个是insert日志一个是update日志 3 个记录隐藏列字段 DB_TRX_ID 6 byte最近修改( 修改/插入 )事务ID记录创建这条记录/最后一次修改该记录的事务ID。DB_ROLL_PTR : 7 byte回滚指针指向这条记录的上一个版本简单理解成指向历史版本就行这些数据一般在 undo log 中 DB_ROW_ID : 6 byte隐含的自增ID隐藏主键如果数据表没有主键 InnoDB 会自动以DB_ROW_ID 产生一个聚簇索引。补充实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除而是删除flag变了。 假设测试表结构是 mysql create table if not exists student( name varchar ( 11 ) not null , age int not null ); mysql insert into student (name, age) values ( 张三 , 28 ); Query OK, 1 row affected ( 0.05 sec) mysql select * from student; ------------- | name | age | ------------- | 张三 | 28 | ------------- 1 row in set ( 0.00 sec) 上面描述的意思是 name age DB_TRX_ID(创建该记录的事务ID) DB_ROW_ID(隐式主键) DB_ROLL_PTR(回滚指针) 张三 28 null 1        null 我们目前并不知道创建该记录的事务 ID 隐式主键我们就默认设置成 null 1 。第一条记录也没有其他版本我们设置回滚指针为null 。 undo 日志 这里不想细讲但是有一件事情得说清楚 MySQL 将来是以服务进程的方式在内存中运行。我们之前所讲的所有机制索引事务隔离性日志等都是在内存中完成的即在 MySQL 内部的相关缓冲区中保存相关数据完成各种判断操作。然后在合适的时候将相关数据刷新到磁盘当中的。 所以我们这里理解 undo log 简单理解成就是 MySQL 中的一段内存缓冲区用来保存日志数据的就行。 模拟 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提交释放锁。 这样我们就有了一个基于链表记录的历史版本链。所谓的回滚无非就是用历史数据覆盖当前数据。 上面的一个一个版本我们可以称之为一个一个的快照。   PS  上面是以更新 upadte主讲的,如果是delete 呢一样的别忘了删数据不是清空而是设置 flag为删除即可。也可以形成版本。 如果是insert 呢因为 insert 是插入也就是之前没有数据那么 insert 也就没有历史版本。但是一般为了回滚操作insert 的数据也是要被放入 undo log 中如果当前事务 commit 了那么这个 undo log 的历史 insert记录就可以被清空了。insert的数据也会放进去但是里面是相反的即delete所以回滚的话就删除掉了 总结一下也就是我们可以理解成 update 和 delete 可以形成版本链 insert 暂时不考虑。 那么select呢 首先 select 不会对数据做任何修改所以为 select 维护多版本没有意义。不过此时有个问题就是 select 读取是读取最新的版本呢还是读取历史版本 当前读读取最新的记录就是当前读。增删改都叫做当前读 select 也有可能当前读比如 select lock in share mode(共享锁 ), select for update 这个好理解我们后面不讨论 快照读读取历史版本 ( 一般而言 ) 就叫做快照读。 ( 这个我们后面重点讨论 ) 我们可以看到在多个事务同时删改查的时候都是当前读是要加锁的。那同时有 select 过来如果也要读取最新版( 当前读 ) 那么也就需要加锁这就是串行化。 但如果是快照读读取历史版本的话是不受加锁限制的。也就是可以并行执行换言之提高了效率即MVCC的意义所在。 那么是什么决定了 select 是当前读还是快照读呢隔离级别 ! 那为什么要有隔离级别呢 事务都是原子的。所以无论如何事务总有先有后。 但是经过上面的操作我们发现事务从 begin-CURD-commit 是有一个阶段的。也就是事务有执行前执行中执行后的阶段。但不管怎么启动多个事务总是有先有后的。 那么多个事务在执行中 CURD 操作是会交织在一起的。那么为了保证事务的 “ 有先有后 ” 是不是应该让不同的事务看到它该看到的内容这就是所谓的隔离性与隔离级别要解决的问题。 先来的事务应不应该看到后来的事务所做的修改呢 ? 那么如何保证不同的事务看到不同的内容呢也就是如何如何实现隔离级别 Read View Read View 就是事务进行 快照读 操作的时候生产的 读视图 (Read View) 在该事务执行的快照读的那一刻会生成数据库系统当前的一个快照记录并维护系统当前活跃事务的ID( 当每个事务开启时都会被分配一个ID, 这个 ID 是递增的所以最新的事务 ID值越大) Read View 在 MySQL 源码中, 就是一个类本质是用来进行可见性判断的。 即当我们某个事务执行快照读的时候对该记录创建一个 Read View 读视图把它比作条件 ,用来判断当前事务能够看到哪个版本的数据既可能是当前最新的数据也有可能是该行记录的 undo log 里面的某个版本的数据。 PS视图数据也是内存级的但是改增加/删除/更改视图的数据也会改变原始表的数据反之一样。原始的表我们称为 基表 下面是 ReadView 结构 , 但为了减少负担我们简化一下 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 生成时刻系统正活跃的事务 ID up_limit_id ; // 记录 m_ids 列表中事务 ID 最小的 ID( 没有写错 ) low_limit_id ; //ReadView 生成时刻系统尚未分配的下一个事务 ID 也就是目前已出现过的事务 ID 的 最大值 1( 也没有写错 ) creator_trx_id // 创建该 ReadView 的事务 ID 我们在实际读取数据版本链的时候是能读取到每一个版本对应的事务 ID 的即当前记录的DB_TRX_ID 。 那么我们现在手里面有的东西就有当前快照读的 ReadView 和 版本链中的某一个记录的 DB_TRX_ID 。 所以现在的问题就是当前快照读应不应该读到当前版本记录。一张图解决所有问题 如果查到不应该看到当前版本接下来就是遍历下一个版本直到符合条件即可以看到。上面的readview 是当你进行 select的时候会自动形成。 整体流程 假设当前有条记录 事务操作  事务4修改name(张三) 变成name(李四) 当 事务2 对某行数据执行了 快照读 数据库为该行数据生成一个 Read View 读视图 此时版本链是 只有事务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_ID 4 // 比较步骤 DB_TRX_ID 4 up_limit_id 1 ? 不小于下一步 DB_TRX_ID 4 low_limit_id ( 5 ) ? 不大于下一步 m_ids . contains ( DB_TRX_ID ) ? 不包含说明事务 4 不在当前的活跃事务中。 // 结论 故事务 4 的更改应该看到。 所以事务 2 能读到的最新数据记录是事务 4 所提交的版本而事务 4 提交的版本也是全局角度上最新的版本。 RR 与 RC的本质区别 当前读和快照读在RR级别下的区别 select * from user lock in share mode ,以加共享锁方式进行读取对应的就是当前读。 -- 设置 RR 模式下测试 mysql set global transaction isolation level REPEATABLE READ; Query OK, 0 rows affected ( 0.00 sec) -- 重启终端 mysql select tx_isolation; ----------------- | tx_isolation | ----------------- | REPEATABLE-READ | ----------------- 1 row in set , 1 warning ( 0.00 sec) -- 依旧用之前的表 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; -- 插入一条记录用来测试 mysql insert into user (id, age, name) values ( 1 , 15 , 黄蓉 ); Query OK, 1 row affected ( 0.00 sec) 测试用例1-表1 事务 A 操作 事务 A 描 述 事务 B 描述 事务 B 操作 begin 开启事务 开启事务 begin select * from user 快照读 ( 无影响 ) 查询 快照读查询 select * from user update user set age18 where id1 ; 更新 age18 commit 提交事务 select 快照读 , 没有读到 age18 select * from user select lock in share mode 当前读 , 读到 age18 select * from user lock in share mode 测试用例2-表2 事务 A 操作 事务 A 描 述 事务 B 描述 事务 B 操作 begin 开启事务 开启事务 begin select * from user 快照读 查到 age18 update user set age28 where id1 ; 更新 age28 commit 提交事务 select 快照读 age28 select * from user select lock in share mode 当前读 age28 select * from user lock in share mode 用例1与用例2 唯一区别仅仅是 表 1 的事务 B 在事务 A 修改 age 前 快照读 过一次 age 数据 而 表 2 的事务 B 在事务 A 修改 age 前没有进行过快照读。 结论  事务中快照读的结果是非常依赖该事务首次出现快照读的地方即某个事务中首次出现快照读决定该事务后续快照读结果的能力。delete同样如此。 RR 与 RC的本质区别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.dnsts.com.cn/news/33045.html

相关文章:

  • 营销型网站建设目的和意义济南住建局官方网站
  • 上传的网站打不开wordpress插件汉化教程视频
  • 北京高端网站wordpress下载类主题系统主题
  • 自助建站竹子易书网上书城网站建设方案
  • 公众号怎么做微网站凡客v 网上商城
  • 网上做兼职的网站有哪些建立网店
  • 网站域名是什有什么字体设计的网站
  • 当当网网站的建设过程php 企业网站模板
  • 公司怎么制作网站企业网站搭建及优化
  • 个人网站怎么快速推广公众号运营总结
  • 做加盟正规网站微信公众号小程序搭建
  • 做网站卖流量无锡君通科技服务有限公司
  • 广州网站建设优化方案深圳品牌网站制作
  • 北京移动端网站百度点击软件找名风
  • 哪个网站科技新闻好在百度备案网站
  • 旅行社网站营销建设英文wordpress变中文
  • 网站安全检测中心广告传媒公司黄页
  • 建设企业网站要多少钱如何增加网站的流量
  • 网站定制开发注意事项做网站的前端是做什么
  • 甘肃住房和城乡建设局网站网站title怎么修改
  • 自助建站信息发布网企业医院做网站的好处
  • 通州区网站建设固定ip做网站路由设置
  • 哪有免费做网站广西网站建设产品介绍
  • 专业做图片制作网站有哪些做免费的视频网站可以赚钱吗
  • 网站特殊字体国外专业做集装箱别墅网站
  • 公司网站可以不买域名吗网站图片设计制作
  • 北京康迪建设监理咨询有限公司网站东莞网络营销十年乐云seo
  • 营销策划的内容包括哪些seo网站推广策略
  • 海报设计论文seo技术培训南阳
  • 网站建设启凡如何建立外卖网站