《深入浅出MySQL学习笔记-事务控制、锁定语句及分布式事务》
默认情况下,行锁和表锁都是自动获得,不需要额外的命令,但有些情况用户需要明确的进行锁表或者事务控制,以保证整个事务完整性。
引擎 | 锁 | 特点 |
---|---|---|
MyISAM、MEMORY | 表级锁 | 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 |
BDB | 页级锁定 | 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 |
InnoDB | 行级锁定 | 开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般 |
14.1 LOCK TABLE和UNLOCK TABLE
LOCK TABLE能锁定用于当前线程的表,如果表被其他线程锁定,当前线程会等待直到所由锁定为止。
UNLOCK TABLE可以释放当前线程获得的任何锁定,当前线程执行另一个LOCK TABLE时或当服务器连接关闭时,所有当前线程锁定的表被隐含地解锁。
eg: LOCK TABLES tablename [as t] {READ [LOCAL]|[LOW_PRIORITY]WRITE} [,tablename2 …]
UNLOCK TABLES
排它锁:也称独占锁、写锁或X锁,若sessionA获得某数据表的排他锁权限,那么sessionA只能对该表进行读取或修改,其他session既不能读取也不能修改该表,更不能对该表加任何类型的锁,直到sessionA释放排它锁权限。加锁方式:lock tables tablename write;
共享锁:也称读锁或S锁,若sessionA获得某数据表的共享锁权限,那么任何session(包括sessionA)只能对该表进行读取,不能修改该表,sessionA可以继续对该数据表加X锁,其他session可以对该数据表继续加S锁但不能加X锁,直到sessionA释放共享锁权限。加锁方式:lock tables tablename read;
14.2 事务控制
MYSQL通过一下语句支持本地事务:
START TRANSCATION | BEGIN [WORK] #开始一项新事务
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]#提交事务,CHAIN会立即启动一个新事务,release会断开和服务器的连接
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO]RELEASE]#回滚事务
SET AUTOCOMMIT={0|1}#修改提交方式,如果设置为0则需手动提交
默认情况下 MySQL是自动提交的,若需要明确的commit和rollback来提交和回滚事务,那就需要明确的事务控制命令来开始事务。
如果在锁表期间用START TRANSACTION 命令开始一个新事务,会造成一个隐含的unlock tables被执行。因此在用一个事务中最好不用不同引擎的表,否则ROLLBACK时需要对非事务性的表进行特别处理,因为COMMIT, ROOLBACK只能对事务类型表进行提交和回滚。
通常只对提交的事务记录到二进制的日志中,但如果一个事物中包含飞事务类型的表,则回滚操作记录也会被记录到二进制日志中,确保非事务类型表的更新可以被复制到从数据库中。
在事务中可以通过定义SAVEPOINT,指定回滚事务的一个部分,但不能指定提交事务的一个部分,对复杂的应用可定义多个不同的SAVEPOINT来满足不同条件下的回滚。
定义SAVEPOINT: SAVEPOINT test;
删除SAVEPOINT: RELEASE SAVEPOINT test
14.3.1 分布式事务的原理
MySQL使用分布式事务应用程序涉及一个或多个资源管理器和事务管理器。
资源管理器RM用于提供通向事务资源的途径,数据库服务器是一种资源管理器,他必须可以提交或回滚RM管理的事务。
事务管理器TM用于协调作为一个分布式事务一部分的事务,TM与管理每个事务的RMs通信,在一个分布式事务中,单个事务均是分布式事务的分支事务。分布式事务和各分支通过一种命名方法进行标识。
MySQL执行XA MySQL时,MySQL服务器相当于一个用于管理分布式事务的资源管理器。与MySQL服务器连接的客户端相当于事务管理器。
执行分布式事务过程分两阶段提交,发生时间在由分布式事务各个分支进行的行动已被执行之后。
一阶段:所有分支预备好,他们被TM告知要准备提交,通常意味着用于管理分支的每个RM会记录对于被稳定保存的分支的行动。
二阶段:TM告知RMs是否要提交或回滚,如果在预备分支时所有的分支指示他们能提交,则所有的分支被告知要提交,若预备时有任何分支指示他不能提交,则所有分支被告知回滚。
14.3.2 分布式事务的语法
xid是一个XA事务标识符,xid :gtrid [,bqual [, formatID]],gtrid是一个分布式事务标识符,相同分布式事务应该适应相同的gtrid,这样可以明确知道XA事务属于哪个分布式事务。bqual是一个分支限定符,默认值时空串,对于一个分布式事务中的每个分支事务,bqual值必须是唯一的。formatID是一个数字,用于表示gtrid和bqual值使用的格式,默认值为1.下面为常用分布式事务语法:
(1)XA {START|BEGIN}xid [JIOIN|RESUME]#启动带给定xid值的XA事务
(2)XA END xid [SUSPEND [FOR MIGRATE]]#此处end是进入IDLE状态
XA PREPARE xid#使事务进入PREPARE状态,此为提交的第一阶段
(3)XA COMMIT xid [ONE PHASE]#提交具体事务
XA ROLLBACK xid#回滚具体事务
XA RECOVER#返回当前数据库中处于PREPARE状态的分支事务的详细信息
分布式的关键在于如何确保分布式事务的完整性,以及某分支出现问题时的故障解决。
14.3.3 存在的问题
若分支事务达到prepare状态时,数据库异常超重新启动服务器重新启动以后,可以继续对分支事务进行提交或者回滚操作,但是提交的事务没写binlog,存在一定隐患可能导致使用binlog恢复丢失部分数据。
如果分支事务的客户端连接异常终止,那么数据库恢自动回滚未完成的分支事务,如果此时分支事务已经执行到prepare状态,那么这个分布式事务的其他分支可能已经成功提交,如果某个分支回滚,可能导致分布式事务的不完整,丢失部分分支事务的内容。
如果分支事务在执行到prepare状态时,数据库异常且不能正常启动,需要使用备份和binlog来恢复数据,那么在prepare状态的分支事务因为并没有记录到binlog,所以不能通过binlog进行恢复,数据库恢复后将丢失这部分数据。
总之:MySQL分布式事务还存在较严重缺陷,在数据库或应用异常情况先可能导致分布式事务不完整,,根据实际对数据完整性的要求可选择是否使用。