文章详情

短信预约信息系统项目管理师 报名、考试、查分时间动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

MySQL学习笔记(13):锁和事务

2015-05-30 16:58

关注

MySQL学习笔记(13):锁和事务

本文更新于2019-09-22,使用MySQL 5.7,操作系统为Deepin 15.4。

目录

锁概述

MyISAM和MEMORY存储引擎使用表级锁。BDB存储引擎进使用页级锁,但也支持表级锁。InnoDB存储引擎默认使用行级锁,也支持表级锁。

默认情况下,表级锁和行级锁都是自动获取的。但在有些情况下,用户需要明确进行锁定。

MyISAM表级锁

表级锁有两种模式:

加锁,如果表已被其他线程锁定,则当前线程会等待直至获得锁:

LOCK TABLE|TABLES
tablename [AS alias] {READ [LOCAL]}|{[LOW_PRIORITY] WRITE}
[, ...]

加锁时指定LOCAL,则允许在满足MyISAM表并发插入条件(使用变量concurrent_insert控制)的情况下,其他用户在表尾并发插入记录。加锁时,需一次锁定所有用到的表,且同一个表在SQL语句中出现多少次,就要通过与SQL语句中相同的别名锁定多少次(使用AS)。加锁后,只能访问加锁的表,且不支持锁升级(即如果是读锁,那么只能执行读操作,不能执行写操作)。

MyISAM在执行读操作(SELECT)前,会自动给涉及的所有表加读锁,在执行写操作(UPDATEDELETEINSERT)前,会自动给涉及的所有表加写锁。

即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁之前。可以使用max_write_lock_count给予读请求获得锁的机会,或使用以下方法改变请求优先级:

解锁,释放当前线程获得的所有锁:

UNLOCK TABLES

如在锁表期间,当前线程执行另一个LOCK TABLESSTART TRANSACTION(对InnoDB存储引擎),或与服务器的连接被关闭时,会隐含地执行UNLOCK TABLES

通过SHOW STATUS LIKE "table_locks%"查看表级锁使用情况。table_locks_waited比较高说明存在较严重的表级锁争用。

InnoDB行级锁

可以通过SHOW STATUS LIKE "innodb_row_lock%",或查看information_schema中相关的表,或通过设置InnoDB Monitors查看行级锁争夺情况。

InnoDB实现了两种类型的行级锁:

另外,为了允许行级锁和表级锁共存,InoDB还有两种内部使用的意向锁,二者都是表锁:

InoDB行级锁模式兼容性如下(纵向是当前锁模式,横向是请求锁模式):

X IX S IS
X 冲突 冲突 冲突 冲突
IX 冲突 兼容 冲突 兼容
S 冲突 冲突 兼容 兼容
IS 冲突 兼容 兼容 兼容

对于UPDATEDELETEINSERT语句会自动给涉及数据集加排他锁(X)。对普通SELECT语句不会加任何锁,可通过select_statement LOCK IN SHARE MODE加共享锁或select_statement FOR UPDATE加排他锁,并需进行提交或回滚。

意向锁是InnoDB自动加的。

InnoDB行级锁是通过给索引上的索引项或间隙加锁来实现的,共分三种:

InnoDB行级锁的特点,需注意如下问题:

InnoDB存储引擎中不同SQL在不同隔离级别下的锁比较(off/on指变量innodb_locks_unsafe_for_binlog的值):

SQL 条件 未提交读 已提交读 可重复读 可序列化
SELECT 相等 无锁 一致性读/无锁 一致性读/无锁 共享锁
SELECT 范围 无锁 一致性读/无锁 一致性读/无锁 共享Next-Key锁
UPDATE 相等 排他锁 排他锁 排他锁 排他锁
UPDATE 范围 排他Next-Key锁 排他Next-Key锁 排他Next-Key锁 排他Next-Key锁
INSERT 排他锁 排他锁 排他锁 排他锁
REPLACE 无键冲突 排他锁 排他锁 排他锁 排他锁
REPLACE 键冲突 排他Next-Key锁 排他Next-Key锁 排他Next-Key锁 排他Next-Key锁
DELETE 相等 排他锁 排他锁 排他锁 排他锁
DELETE 范围 排他Next-Key锁 排他Next-Key锁 排他Next-Key锁 排他Next-Key锁
SELECT ... FROM ... LOCK IN SHARE MODE 相等 共享锁 共享锁 共享锁 共享锁
SELECT ... FROM ... LOCK IN SHARE MODE 范围 共享锁 共享锁 共享Next-Key锁 共享Next-Key锁
SELECT ... FROM ... FOR UPDATE 相等 排他锁 排他锁 排他锁 排他锁
SELECT ... FROM ... FOR UPDATE 范围 排他锁 排他锁 排他Next-Key锁 排他Next-Key锁
INSERT INTO ... SELECT ...(源表锁) off 共享Next-Key锁 共享Next-Key锁 共享Next-Key锁 共享Next-Key锁
INSERT INTO ... SELECT ...(源表锁) on 无锁 一致性读/无锁 一致性读/无锁 共享Next-Key锁
CREATE TABLE ... SELECT ...(源表锁) off 共享Next-Key锁 共享Next-Key锁 共享Next-Key锁 共享Next-Key锁
CREATE TABLE ... SELECT ...(源表锁) on 无锁 一致性读/无锁 一致性读/无锁 共享Next-Key锁

INSERT INTO ... SELECT ...CREATE TABLE ... SELECT ...叫做不确定的SQL,属于不安全的SQL,不推荐使用。如确实需要使用,又不希望因加锁对源表并发更新产生影响,可使用以下方法:

InnoDB表级锁

以下两种情况可以考虑使用表级锁:

使用表级锁需要注意:

死锁

MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。InnoDB,除单个SQL组成的事务外,锁是逐步获得的,这就决定了InnoDB可能发生死锁。

发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并回滚,另一个事务获得锁继续完成事务。但在涉及外部锁或涉及表级锁的情况下,InnoDB并不能完全自动检测到死锁,这需要通过设置锁等待超时参数innodb_lock_wait_timeout解决。

减少锁冲突和死锁的方法:

可以使用SHOW ENGINE INNODB STATUS查看最后一个死锁产生的原因。

事务

事务概述

事务的ACID属性:

并发事务处理的问题:

防止更新丢失是应用的责任,需要应用对要更新的数据加锁来解决。脏读、不可重复读、幻读其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。事务隔离实质上是使事务在一定程度上串行化。数据库实现事务隔离的方式基本上分两种:

有以下4个事务隔离级别:

隔离级别 读一致性 脏读 不可重复读 幻读
未提交读(Read Uncommitted) 最低级别,只能保证不读取物理上损坏的数据
已提交读(Read Committed) 语句级
可重复读(Repeatable read) 事务级
可序列化(Serializable) 最高级别,事务级

可使用语句改变事务隔离级别:

SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED}|{READ COMITTED}|{REPEATABLE READ}|SERIALIZABLE

InnoDB事务

默认情况下,InnoDB是自动提交事务的,即每执行一条语句提交一次事务。可设置变量autocommit指定是否自动提交。

在同一个事务中,最好不要使用不同存储引擎的表,否则ROLLBACK需要对非事务表进行特别的处理,因为COMMITROLLBACK只能对事务表有效。通常情况下,只对提交的事务记录到二进制日志中,但如果一个事务中包含非事务表,那么回滚的操作也会被记录到二进制日志中,以确保非事务表的更新也可以被复制到从数据库中。

所有的DDL语句都是不能回滚的,并且部分DDL语句会造成隐式的事务提交。

开始事务:

{START TRANSACTION}|{BEGIN [WORK]}

提交事务:

COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]

回滚事务,可以回滚到指定的savepointname。注意,可以回滚事务的一个部分,但不能提交事务的一个部分:

ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] [TO SAVEPOINT savepointname]

CHAINRELEASE子句用于定义事务提交或回滚后的操作:CHAIN会立即启动一个新事务,并且和原先的事务有相同的隔离级别;RELEASE会断开客户端和服务器之间的连接。默认是NO CHAIN NO RELEASE

定义SAVEPOINT。可以定义多个SAVEPOINT,如果定义了相同名字的SAVEPOINT,则后面定义的覆盖前面定义的:

SAVEPOINT savepointname

删除SAVEPOINT

RELEASE SAVEPOINT savepointname

分布式事务

当前分布式事务只支持InnoDB存储引擎。

一个分布式事务会涉及多个分支事务(XA事务),这些XA事务必须一起被提交,或一起被回滚。

使用分布式事务的应用程序涉及一个或多个资源管理器和一个事务管理器:

执行分布式事务的过程使用两阶段提交:

  1. 第一阶段,所有分支事务被预备好,即它们被TM告知准备提交。
  2. 第二阶段,TM告知所有RM需要提交还是回滚。如果在第一阶段,所有XA事务指示都能提交,则在第二阶段所有XA事务都被告知需要提交;如在第一阶段,任一XA事务指示不能提交,则在第二阶段所有XA事务都被告知需要回滚。

启动XA事务:

XA START|BEGIN xid [JOIN|RESUME]

每个XA事务必须有一个唯一的xid,该值不能被其他的XA事务使用。xid由客户端提供,或由MySQL服务器生成,包含3个部分:"gtrid"[,"bqual"[,formatID]]

使XA事务进入PREPARE状态,也即两阶段提交的第一阶段:

XA END xid [SUSPEND [FOR MIGRATE]];
XA PREPARE xid;

提交XA事务,进入两阶段提交的第二阶段:

XA COMMIT xid [ONE PHASE]

回滚XA事务,进入两阶段提交的第二阶段:

XA ROLLBACK xid

返回当前数据库中处于PREPARE状态的XA事务详细信息:

XA RECOVER

MySQL的分布式事务还存在比较严重的缺陷:

  1. 如果XA事务在到达PREPARE状态时,数据库异常重启后,可以继续对XA事务进行提交或回滚,但提交的事务没有写如binlog,可能导致使用binlog恢复时丢失部分数据。如果存在复制的数据库,则有可能导致主从数据库的数据不一致。
  2. 如果某个XA事务的客户端连接异常终止,数据库会自动回滚未完成的XA事务。如果此时XA事务已经执行到PREPARE状态,那么这个分布式事务的其他XA事务可能已经提交。这个XA事务回滚,会导致分布式事务不完整。
阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯