《高性能MySQL》 第一章(并发控制、事务、存储引擎)

并发控制(数据库中的表的删除和修改)
问题1:
email box中,如果同时投递邮件会发生混乱。
解决:
为了避免会在投递邮件时锁住邮箱,必须等待锁释放才能继续投递。
不足:
任意时刻只能一个进程修改邮箱内容,不适用于大容量的邮箱系统
问题2:
当某个客户在读取邮箱时,另一个客户试图删除某个邮件,读的客户可能会报错退出,也可能读取到不一致的邮箱数据
解决:
共享锁(读锁):共享的、互不阻塞的,多个客户可以在同一时刻同时读取数据,而互不干扰(问题2)
排他锁(写锁):排他的,会阻塞其他的读锁和写锁,保证只有一个用户写入(问题1)
优化方法:
只锁定需要修改的部分或者只对会修改的数据片进行精确的锁定,但不要把过多的资源用到锁的开销中,所以 要在锁的开销和数据的安全性之间寻求平衡。

两种重要的锁策略:
表锁:最基本、开销最小的策略,会锁定整张表。一个用户在对表进行写操作时,需要先获得写锁,会阻塞其他用户对该表的所有读写操作。只有没有写锁时其他读取的用户才会获得读锁,读锁之间不互相阻塞。(问题:如果一个用户正在读取时,另一个用户修改了数据如何避免?)
锁队列,依次进行各个请求,但是写锁可以插入到读锁前面,反之则不行。
行级锁:可以最大程度地支持并发处理,但是锁开销最大。


事务
事务就是一组原子性的SQl查询。如果每一句查询语句都能执行,则执行所有查询;如果有任一条语句无法执行,那么所有语句都不会执行。要么全部成功,要么全部失败。
问题:
假设银行数据库有两张表:支票表和储蓄表,要从某用户支票账户转移200美元到储蓄账户,需要三个步骤:
①检查支票账户余额高于200美元;②从支票账户余额中减去200美元;③从储蓄账户余额中增加200美元
将这三个步骤打包成一个整体,就是一个事务。
假如执行到某一语句服务器崩溃了,或者有其他语句执行影响了账户余额,会使用户或者银行造成损失。
解决:
只是空谈事务的概念远远不够,需要事务处理系统满足:原子性、一致性、隔离性、持久性。
原子性:
一个事务必须为不可分割的最小工作单元,而不能只执行其中的一部分。
一致性:
总是从一个一致的状态转换到另外一个一致的状态。(即使系统崩溃了,由于事务没有提交,所做的修改不会保存而不会造成损失)
隔离性:
通常来说,一个事务所做的修改在最终提交之前,对其他事务是不可见的。(与隔离级别有关)
持久性:
一旦事务提交,则其所做的修改就会永久保存到数据库。实际上持久性不可能做到100%。
不足:
需要更强的CPU处理能力,更大的内存,更多的磁盘空间。如果并不需要事务的查询类,可以选择非事务性的存储引擎。

隔离级别:
①READ UNCOMMITTED(未提交读)
事务中的修改即使没有提交,对其他事务也是可见的。因从性能上来说并没有优势,并且没有其他级别的好处,所以一般很少使用
②READ COMMITED(提交读)
大多数数据库默认的隔离级别(MySQL不是)。事务只能看见已经提交的事务所做的修改,在提交之前对其他事务是不可见的。不可重复读
③REPEATABLE READ(可重复读)
解决了脏读的问题,保证了在同一事务中多次读取同样的记录的结果是一致的。但仍存在幻读问题:某个事务读取记录时,另一个事务插入了新的记录,当前事务再次读取记录时会产生幻行
可重复读与不可重复读的区别:不可重复读的重点在修改,是指在一个事务前后两次读取的某个记录的结果并不一致;幻读的重点在新增,是指同样的条件两次读取出来的记录数不同。
④SERIALIZABLE(可串行化)
是最高的隔离级别,通过强制事务串行执行,避免了幻读的问题。在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。很少用到这个隔离级别,除非在非常需要确保数据的一致性而且可以接受没有并发的情况

死锁:
问题:
两个或多个事务在同一资源上相互作用,并请求锁定对方占用,从而导致恶性循环。当多个事务试图以不同的顺序锁定资源时,就会产生死锁。
解决:
数据库系统实现了死锁检测和死锁超时机制。一种返回一个错误;一种在超时后放弃锁请求。InnoDB采用的是将持有最少行级排他锁的事务进行回滚。
分析产生的原因:
一种是真正的数据冲突引起的;另一种是由于存储引擎的实现方式导致的。

事务日志:
磁盘不直接记录数据本身。而是将修改行为记录到持久在硬盘里的事务日志。采用追加方式。系统崩溃时可以自动恢复这部分修改的数据。

MySQL中的事务:
MySQL提供了两种事务型存储引擎:InnoDB和NDB Cluster
自动提交:
MySQL默认采用自动提交模式。即如果没有明确说开始一个事务,那么每个查询都会当做一个事务执行提交操作。通过设置AUTOCOMMIT变量来启用或禁用
当禁用时,所有的查询都是在同一个事务中,知道显式地执行COMMIT提交或者ROLLBACK回滚时该事务结束,同时又开始了另一个新的事务。
对非事务的表,修改AUTOCOMMIT不会有任何影响。
有一些命令在执行之前会强制执行COMMIT提交当前的活动事务。如ALTER、TABLE、LOCK TABLES等。
设置隔离级别可以通过执行:
SET SESSION TRANSACTION ISOLATION LEVEL + 隔离级别
来实现
在事务中混合使用存储引擎:
在同一事务中使用多种存储引擎是不可靠的,如果混合使用了事务型和非事务型的表,会导致在事务回滚时非事务型的表上的变更无法撤销。
隐式和显式锁定:
隐式锁定:在事务执行时随时都可以执行锁定,InnoDB会根据隔离级别在需要的时候加锁。
显式锁定:支持通过LOCK TABLES和UNLOCK TABLES语句,但是在InnoDB中不但没有必要还会严重影响性能。

多版本并发控制:
多版本并发控制(MVCC)是行级锁的一个变种,在很多情况下避免加锁,节省开销,大都实现非阻塞的读操作和锁定必要行的写操作。
实现原理:
每行记录后面保存两个隐藏行:一个保存了创建时间,一个保存了删除时间(过期时间)。时间的值为系统版本号。每当开始一个新得事务,系统版本号就会自动递增,并作为事务的版本号。在执行查询、插入、删除、更新时,只需要记录下版本号或者比较当前版本号和需要查询行的版本号比较大小即可。
优点:
数据操作简单,性能好,保证读取到的数据符合标准。
不足:
每行记录都需要额外的储存空间,需要更多的行检查工作和一些额外的维护工作

MySQL的存储引擎
InnoDB、MyISAM...

总结:
MySQL上层是服务器层的服务和查询执行引擎,下层时存储引擎。两层之间来回交互。
并发控制的锁结构解决了多个用户对同一数据操作时出现的问题;
事务是一系列不可分割的SQL语句的全集,同样存在上面的问题,于是有了隔离级别的概念。但是仍会存在死锁现象,存储引擎也有相应的解决措施。
在恢复数据时可以通过事务日志来恢复而不必完全将数据记录到磁盘上。
各个存储引擎各有利弊,依情况而定,在不知道选择哪一款时最好选择InnoDB。

猜你喜欢

转载自blog.csdn.net/weixin_40475469/article/details/78650350