锁
锁是计算机协调多个进程或线程并发访问某一资源的机制。锁保证数据并发访问的一致性、有效性;锁冲突也是影响数据库并发访问性能的一个重要因素。锁是Mysql在服务器层和存储引擎层的的并发控制。
加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否是否已解除、释放锁等
- 锁粒度:
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
- 锁的读写类型:
- 读锁:也称共享锁,只读不可写(包括当前事务),多个读互不阻塞
- 写锁:也称独占锁、排它锁,写锁会阻塞其它事务(不包括当前事务)的读和它锁
- 兼容:如果事务T1获得了行r的共享锁,那么事务T2也可以获得行r的共享锁,这种情况称之为锁兼容,事务T3需要等行r释放共享锁,才能获得排他锁,这叫锁不兼容。
- 实现
- 存储引擎:自行实现其锁策略和锁粒度
- 服务器级:实现了锁,表级锁,用户可显式请求
- 分类:
- 隐式锁:由存储引擎自动施加锁
- 显式锁:用户手动请求
显式使用锁
- LOCK TABLES 加锁
LOCK TABLES
tbl_name [[AS] alias] lock_type
[, tbl_name [[AS] alias] lock_type] ...
lock_type:
READ [LOCAL]
| [LOW_PRIORITY] WRITE
示例
lock tables students write;
- 解锁
UNLOCK TABLES;
- 关闭正在打开的表(清除查询缓存),通常在备份前加全局读锁
#全局锁
FLUSH TABLES [tb_name[,...]] [WITH READ LOCK]
- 查询时加写或读锁
SELECT clause [FOR UPDATE | LOCK IN SHARE MODE]
查看当前事务锁的信息
information_schema这个库的3张表:
INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS
- 死锁
死锁:是指两个或以上的事务在执行过程中,因争夺资源造成的一种互相等待的现象.
解决1:将任何的等待转化为回滚,并且事务重新开始。但这会浪费性能
解决2:超时。当一个等待时间超过设置的值时,事务进行回滚。参数:innodb_lock_wait_timeout
事务
事务Transactions:一组原子性的SQL语句,或一个独立工作单元
事务日志:记录事务信息,实现undo,redo等故障恢复功能
- ACID特性:
- A:atomicity原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚
- C:consistency一致性;数据库总是从一个一致性状态转换为另一个一致性状态
- I:Isolation隔离性;一个事务所做出的操作在提交之前,是不能为其它事务所见;隔离有多种隔离级别,实现并发
- D:durability持久性;一旦事务提交,其所做的修改会永久保存于数据库中
- Transaction生命周期
事务的分类
扁平事务、带有保存点的扁平事务、链事务、嵌套事务、分布式事务
1. 扁平事务:最简单,使用最多的事务
#情况1:成功执行,提交
BEGIN WORK
...
Operation ...
...
COMMIT WORK
#情况2:发生错误或超时,回滚
BEGIN WORK
...
Operation ...
(Errot !)
...
ROLLBACK WORK
扁平事务无法分段执行,要么全提交,要么全回滚。
比如说A-->B-->C-->D,其中执行了A-->B-->C然后出错了,就得重新来了。
如果想要从B开始,就得使用带有保存点的扁平事务。
- 带有保存点的扁平事务
玩过单机游戏可能就好理解,带有保存点的扁平事务就相当于你的存档,当角色死亡时,可以选择最近的存档,不至于需要从头开始。 - 链事务
有点像带有保存点的扁平事务,但链事务只能回滚到上一个事务。上一个事务的提交触发下一个事务的开始。 - 嵌套事务
由一个顶层事务控制着各层次的事务。顶层事务一般不用于访问数据库等操作,只负责逻辑控制,实际工作由子事务来完成。 - 分布式事务
通常是在分布式环境下运行的扁平事务
启动事务:
- 启动事务:
BEGIN
或
BEGIN WORK
或
START TRANSACTION
- 结束事务:
#提交
COMMIT
#回滚
ROLLBACK
注意:只有事务型存储引擎中的DML语句方能支持此类操作
注意:ROLLBACK回滚后,就得需要重新启动事务了。
注意:事务的回滚只针对DML语句
- 自动提交:
set autocommit={1|0}
默认为1,为0时设为非自动提交
建议:显式请求和提交事务,而不要使用“自动提交”功能 - 事务支持保存点:savepoint
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
事务隔离级别
- 事务隔离级别:从上至下更加严格
READ UNCOMMITTED
浏览访问:可读取到未提交数据,产生脏读READ COMMITTED
游标稳定:可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致REPEATABLE READ
可重复读,多次读取数据都一致,产生幻读,即读取过程中,即使有其它提交的事务修改数据,仍只能读取到未修改前的旧数据。此默认设置SERIALIZABILE
可串行化,未提交的读事务阻塞修改事务,或者未提交的修改事务阻塞读事务。导致并发性能差
MVCC: 多版本并发控制,和事务级别相关
事务隔离级别|脏读可能性|不可重复可能性|幻读可能性|加锁读
-|-|-|-|-
读未提交
read-uncommitted|是|是|是|否
不可重复读
read-committed|否|是|是|否
可重复读
repeatable-read|否|否|是|否
串行化
serializable|否|否|否|是
指定事务隔离级别:
服务器变量tx_isolation指定,默认为REPEATABLE-READ,可在GLOBAL和SESSION级进行设置
#默认值
MariaDB [hellodb]> show variables like '%isolation%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
#临时配置
SET tx_isolation='type'
#type:{READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE }
#配置文件
vim /etc/my.cnf
[mysqld]
transaction-isolation=SERIALIZABLE