mysql的逻辑架构图
最上层:客户端通过用户名,主即命,密码等信息的认证连接到MYSQL服务器,每个客户端连接都会再服务器中拥有一个线程,这个连接的查询只会再这个线程中查询,线程的创建和销毁都由服务器来完成。
第二层:包含大多数核心服务。包括查询、分析、优化、缓存及所有内置函数。还有所有跨存储引擎都在这一层实现:存储过程、触发器、视图等。
第三层:包含了存储引擎。存储引擎负责MYSQL中的数据的存取。服务器通过API与存储引擎进行通信。但每个存储引擎互不通信。
MYSQL的读写中,一般都会出现并发控制的问题。不论是同时写,还是读时对表进行修改等操作,都可能出错。对此问题,我们可以通过实现一个由两种类型的锁组成的锁系统来解决问题。分别为共享(读)锁和排他(写)锁。
表锁是MYSQL中最基本的锁策略,并且是开销最小的策略。它在对数据进行读写时会锁定整个表不被其他用户所用。一种提高共享资源并发的方式是让锁定对象的范围尽量的小,即访问部分数据时表中其它数据还可被访问。例如行级锁可以最大程度地支持并发处理。
事务
事务就是一组原子性的SQL查询,一个独立的工作单元。如果数据库引擎能够成功执行组中所有语句,那么就能执行该组查询。如果有任意一条语句不能被执行,则所有都作废。除了原子性还有一致性,隔离性,持久性。
最经典的银行的转账问题:(从用户A支票账户上转移200到他的储蓄账户)
1.检查支票账户余额高于200元。
2.从支票账户减去200元。
3.在储蓄账户上增加200元。
。。。
这样就很明显了,要么全部执行成功,要么全部回滚到最初的模样。这就是事务了。。吧。。
隔离级别:
隔离级别 | 脏读可能性 | 不可重复可读性 | 幻读可能性 | 加锁读 |
READ UNCOMMITTED(未提交读) | Yes | Yes | Yes | No |
READ COMMITTED(提交读) | No | Yes | Yes | No |
repeatable read(可重复读) | No | No | Yes | No |
SERIALIZABLE(可串行化) | No | No | No | Yes |
死锁是指两个或多个事务在同一资源上相互占用,并请求被对方锁定的资源,从而导致恶性循环的现象。比如两个事务同时执行第一条语句,更新并锁定了同一行数据,接着两个事务都执行操作这行数据的第二条指令,此时两个事务请求的数据被对方锁定,都不放开。叮~死锁。
解决死锁一般有两种办法:
- 死锁检测 (检测到死锁,立即返回一个错误)
- 死锁超时机制 (将持有最少行级排他锁的事务进行回滚)
mysql中的事务
事务是由下层的存储引擎实现的。
MYSQL默认采用自动提交,即每个查询都被当作一个事务执行提交操作。这个可以通过 SHOW VARIABLES LIKE ‘AUTOCOMMIT’; 来查看。通过 SET AUTOCOMMIT=1; 来设置。
为每张表选择合适的存储引擎非常重要。
锁只有在执行提交或者回滚时候才会释放,并且同时释放所有锁。InnoDB会根据隔离级别在需要的时候自动加锁。但为了提高性能,大多数事务型存储引擎实现的都不是简单的行级锁。而是用多版本并发控制(MVCC)。
MVCC是通过保存数据在某个时间点的快照来实现的。
InnoDB的MVCC,通过在每行后面保存两个隐藏的列来实现。
一个列保存行的创建时间。
一个列保存行的过期时间。
此处的时间实际上是系统版本号。 MVCC只在提交读和可重复读两个隔离级别下工作,其他两个MVCC不兼容。
InnoDB只查找版本早于或等于当前事务版本的数据行。
行的删除版本要么未定义,要么大与当前事务版本号。
总结下InnoDB:采用MVCC(版本控制)来支持高并发,并且实现了四个标准的隔离级别,其默认为可重复读,并且通过间隙锁策略防止幻读的出现。
存储引擎的选择很重要,除了InnoDB还有很多引擎,比如以前MYSQL的默认存储引擎为MyISAM,还有第三方存储引擎比如OLTP类引擎,面向列的存储引擎(Infobright),社区存储引擎。一般InnoDB都是正确的选择。如果需要应用不同的存储引擎,需要考虑事务,备份,崩溃恢复等因素。
如果想要将表的存储引擎转换成另一种引擎,有三种比较好的办法:
- mysql> ALTER TABLE mytable ENGINE = InnoDB; 直接使用命令修改
- 使用工具将数据导出到文件,然后修改文件中的CREATE TABLE语句的存储引擎选项。
- 先创建一个新的存储引擎的表。然后利用INSERT…SELECT语法来导入数据。