引言
mysql 并不完美,却足够灵活,能够适应高要求环境。同时,mysql 可以嵌入应用程序中,支持数据仓库,内容索引,部署,高可用的冗余系统,在线事务处理系统等。而mysql 最重要的是它的存储引擎架构,这种架构的设计将查询处理和其他任务的存储、提取分离。这种设计在使用时可以根据性能,特性及特定要求进行数据存储。(来自官网)
——————————————————————————————————————————
mysql 逻辑架构:
mysql 服务器逻辑架构图
链接/线程处理
(最上层):并非mysql独有的,用于连接处理,授权,安全等。
查询缓存 、 解析器、优化器
(第二层):核心层,查询、分析、优化、缓存及所有的内置函数都在这层: 存储过程、触发器、视图等。
存储引擎
(第三层): 负责mysql 中的数据存储和提取。
——————————————————————————————————————————
mysql 中的锁
为什么要使用锁策略?
锁的开销和数据的安全性进行平衡,这种平衡会影响到性能。锁粒度固定的某个级别上,可以为某些特定场景提供更好的性能。但同时也会失去一些场景。不过mysql 可使用多存储引擎的方式。
锁粒度
首先理解锁粒度:
只对修改的数据进行精准的锁定
。并发是为了让锁定的对象更有选择性,只简单锁住需要修改的内容,而不是所有资源。在给定的资源上,锁定的数据越少,并发度越高。因为加锁需要消耗资源,锁的操作众多,检查锁,释放锁,检查是否释放锁,都会增加开销,如果花费大量时间来检查,而不是存储数据,那系统性能就会下降。
读写锁
读写锁:实现并发处理读或者写时,需要实现两类锁来解决问题。
读锁又称共享锁(shared lock), 写锁又称排他锁(exclusive lock)
。读锁是共享的,并不相互阻塞。多个用户在同一时间改同一资源互不干扰。写锁会阻塞其他的写锁和读锁。只有写入完成后,才能保证读取的内容一致。
表锁
表锁:
最基础锁策略,开销最小
。对表进行操作时,需要先获取表中是否有表锁,检测到有时,会获取写锁并阻塞该表的所有读写操作。只要没有写锁后,其他用户才能使用读锁。读并不阻塞。
行级锁
行级锁:
最大程度的支持并发,同时也带来了最大的锁开销
。对表中的某行数据进行加锁。
间隙锁
间隙锁: 主要在InnoDB 内部中并且在可重复读的隔离级别下会出现. InnoDB 不仅仅会锁住查询的行,会对索引中的间隙进行锁定,也可以理解为了解决幻读而出现的锁。
死锁
死锁:
两个或多个事务在同一资源上相互占用并请求锁定对方占用的资源,从而相互等待的现象
。多个事务同时锁定一个资源或者事务以不同的顺序锁定资源都会造成死锁。(InnoDB 引擎有检测死锁的功能,处理方式是将持有最少的排他锁事务进行回滚。同时释放死锁也可以使用超时就方式请求回滚。)
死锁产生有多重性,有些是因为数据冲突,这种无法避免。有些是因为存储引擎的实现方式导致。
——————————————————————————————————————————
事务
什么是事务?
事务是一组原子性SQL 查询,一个独立的工作单元。如果数据库引擎 能够成功对数据库应用该组原子性SQL 查询。那么就会执行该组查询。事务内的语句,要么全部执行成功,要么全部失败。
事务的四大特性(ACID):
原子性:
一个事务必须被视为一个不可分割的最小工作单元
,整个事务要么全部成功,要不都不成功,不可只执行其中的某一部分。
一致性:
数据库执行的结果最终是一致的
,不会因为事务没有提交而修改数据。
隔离性:
在最终提交以后,
执行期对其他的事务不可见
。
持久性:
一旦事务提交后,其所作的修改会永久保存到数据库中
。即使是系统崩溃也不会丢失。
隔离级别
什么是隔离级别?
SQL 中定义了四种隔离级别,每种级别都规定了事务的所需要的修改,事务对其他事务是否可见,对其他事务是否不可见。较低的隔离级别通常可以执行更高的并发,系统开销更低。
-
READ UNCOMMITTED(未提交读)
:
也被称为脏读
。事务中的修改,即便没有提交,对其他事务也是可见的。事务可以读取未提交的数据。性能上没有比其他事务级别好,同时也缺乏其他事务的好处,属于使用较少的一种。 -
READ COMMITTED(提交读)
:
也称为不可重复读
。 事务开始时,只能使用已经提交过的事务的修改内容。即一个事务在开始到提交前,对其他事务不可见。因两次执行同样的查询可能会得到不一样的结果,所以叫不可重复读。 -
REPEATABLE READ(可重复读)
:MYSQL 的默认事务隔离级别,该级别主要解决了脏读的问题。该级别保证在同一个事务中多次读取同样的结果是一致的。但却无法解决
幻读
。
幻读是指在某个事务读取某个范围内的记录时,另一个事务插入了新数据,当之前的事务再次读取该范围记录时产生的数据不一致,也被称为幻行
。 -
SERIALIZABLE(可串行化)
:是最高的隔离级别。通过强制事务的串行化,避免前面幻读问题。这种级别会在读取每一行数据时都加上锁可能会导致超时和锁竞争问题,在没有并发并且需要保证数据的一致性时可考虑使用。
附隔离级别图:
设置隔离级别方式:
mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 修改所有事务的隔离级别,从下一条生效。
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 修改当前会话的隔离级别
事务日志
事务日志是用来提交事务效率的。存储引擎在修改表的数据时,只需要修改其内存的拷贝。再把修改行为记录到持久在硬盘的事务日志中,而不用每次修改数据本身持久到磁盘中。事务持久化以后,内存中被修改的数据在后台慢慢的刷回磁盘中。
mysql中的事务
自动提交(AUTOCOMMIT)
mysql 的默认模式,如果不显示的开启一个事务,那么每个查询都会被当成一个事务执行提交操作。
mysql> SHOW VARIABLES LIKE 'AUTOCOMMIT'; -- 检查自动提交是否开启:
mysql> SET AUTOCOMMIT = 1 ; -- 设置自动提交
1 或者NO 表示启动,0或者OFF 表示禁用。当AUTOCOMMIT = 0 时,所有的查询都在一个事务中,直到显式执行COMMIT 或者ROLLBACK 回滚。该事务结束,并开启一个新的事务。
显示锁定和隐式锁定
InnoDB 会在执行事务时自动加锁,并只有在COMMIT 和 ROLLBACK 以后才会释放资源。锁会在同一个时间释放。 这种由存储引擎加的锁称为隐式锁定。显示锁定主要为人为上锁,如:
mysql> SELECT .... LOCK IN SHARE MODE;
mysql> SELECT .... FOR UPDATE;
这种上锁方式和引擎无关,有自己的用途。属于是在服务器层的实现。并不能代替事务。
(如果引擎是InnoDB 并且关闭了AUTOCOMMIT 可以使用LOCK TABLES ,否则如果在开启的情况下,可能会造成事务与LOCK TABLES 的未知错误)。