成都创新互联网站制作重庆分公司

mysql怎么锁库,数据库锁表如何解锁 mysql

如何对MySQL数据库表进行锁定

服务器由两种表的锁定方法:

创新互联提供高防服务器租用、云服务器、香港服务器、成都西信服务器托管

1.内部锁定

内部锁定可以避免客户机的请求相互干扰——例如,避免客户机的SELECT查询被另一个客户机的UPDATE查询所干扰。也可以利用内部锁定机制防止服务器在利用myisamchk或isamchk检查或修复表时对表的访问。

语法:

锁定表:LOCK TABLES tbl_name {READ | WRITE},[ tbl_name {READ | WRITE},…]

解锁表:UNLOCK TABLES

LOCK TABLES为当前线程锁定表。UNLOCK TABLES释放被当前线程持有的任何锁。当线程发出另外一个LOCK TABLES时,或当服务器的连接被关闭时,当前线程锁定的所有表自动被解锁。

如果一个线程获得在一个表上的一个READ锁,该线程(和所有其他线程)只能从表中读。如果一个线程获得一个表上的一个WRITE锁,那么只有持锁的线程READ或WRITE表,其他线程被阻止。

每个线程等待(没有超时)直到它获得它请求的所有锁。

WRITE锁通常比READ锁有更高的优先级,以确保更改尽快被处理。这意味着,如果一个线程获得READ锁,并且然后另外一个线程请求一个WRITE锁, 随后的READ锁请求将等待直到WRITE线程得到了锁并且释放了它。

显然对于检查,你只需要获得读锁。再者钟情跨下,只能读取表,但不能修改它,因此他也允许其它客户机读取表。对于修复,你必须获得些所以防止任何客户机在你对表进行操作时修改它。

2.外部锁定

服务器还可以使用外部锁定(文件级锁)来防止其它程序在服务器使用表时修改文件。通常,在表的检查操作中服务器将外部锁定与myisamchk或isamchk作合使用。但是,外部锁定在某些系统中是禁用的,因为他不能可靠的进行工作。对运行myisamchk或isamchk所选择的过程取决于服务器是否能使用外部锁定。如果不使用,则必修使用内部锁定协议。

如果服务器用--skip-locking选项运行,则外部锁定禁用。该选项在某些系统中是缺省的,如Linux。可以通过运行mysqladmin variables命令确定服务器是否能够使用外部锁定。检查skip_locking变量的值并按以下方法进行:

如果skip_locking为off,则外部锁定有效您可以继续并运行人和一个实用程序来检查表。服务器和实用程序将合作对表进行访问。但是,运行任何一个实用程序之前,应该使用mysqladmin

flush-tables。为了修复表,应该使用表的修复锁定协议。

如果skip_locaking为on,则禁用外部锁定,所以在myisamchk或isamchk检查修复表示服务器并不知道,最好关闭服务器。如果坚持是服务器保持开启状态,月确保在您使用此表示没有客户机来访问它。必须使用卡党的锁定协议告诉服务器是该表不被其他客户机访问。

检查表的锁定协议

本节只介绍如果使用表的内部锁定。对于检查表的锁定协议,此过程只针对表的检查,不针对表的修复。

1.调用mysql发布下列语句:

$mysql –u root –p db_namemysqlLOCK TABLE tbl_name READ;mysqlFLUSH TABLES;

该锁防止其它客户机在检查时写入该表和修改该表。FLUSH语句导致服务器关闭表的文件,它将刷新仍在告诉缓存中的任何为写入的改变。

2.执行检查过程

$myisamchk tbl_name$ isamchk tbl_name

3.释放表锁

mysqlUNLOCK TABLES;

如果myisamchk或isamchk指出发现该表的问题,将需要执行表的修复。

修复表的锁定协议

这里只介绍如果使用表的内部锁定。修复表的锁定过程类似于检查表的锁定过程,但有两个区别。第一,你必须得到写锁而非读锁。由于你需要修改表,因此根本不允许客户机对其进行访问。第二,必须在执行修复之后发布FLUSH

TABLE语句,因为myisamchk和isamchk建立的新的索引文件,除非再次刷新改表的高速缓存,否则服务器不会注意到这个改变。本例同样适合优化表的过程。

1.调用mysql发布下列语句:

$mysql –u root –p db_namemysqlLOCK TABLE tbl_name WRITE;mysqlFLUSH TABLES;

2.做数据表的拷贝,然后运行myisamchk和isamchk:

$cp tbl_name.* /some/other/dir$myisamchk --recover tbl_name$ isamchk --recover tbl_name

--recover选项只是针对安装而设置的。这些特殊选项的选择将取决与你执行修复的类型。

3.再次刷新高速缓存,并释放表锁:

mysqlFLUSH TABLES;mysqlUNLOCK TABLES;

mysql如何锁库?用什么命令

MySQL 5.1支持对MyISAM和MEMORY表进行表级锁定,对BDB表进行页级锁定,对InnoDB表进行行级锁定。

如果不能同时插入,为了在一个表中进行多次INSERT和SELECT操作,可以在临时表中插入行并且立即用临时表中的记录更新真正的表。

这可用下列代码做到:

mysql LOCK TABLES real_table WRITE, insert_table WRITE;

mysql INSERT INTO real_table SELECT * FROM insert_table;

mysql TRUNCATE TABLE insert_table;

mysql UNLOCK TABLES;

MySQL锁

对表的增删改查,都需要MDL锁,无所不在

MDL读锁之间不互斥,但MDL读写锁互斥

#举个栗子

假设t是一张大表

session1对t执行一个查询(SR)

session2对t执行一个DDL(SU,可能升级到X)

session3对t执行一个查询(SR)

可知session1持有t表的MDL读锁(SR),session1的查询还没有结束的时候,去执行session2的DDL(SU),此时session2需要MDL写锁(SU升级到X,需要X锁),由于MDL读写锁互斥,因此session2需要等待session1释放MDL读锁(SR阻塞X);同时session2对后面的所有MDL读锁互斥(X阻塞SR),因此session2又继续阻塞了session3...

#注释:一开始的DDL能看到的状态是SU,但如果SU的某个阶段被阻塞,会被升级到X,从而引发SR阻塞X,达到实验的效果。但实际测试中,DDL是分阶段的,如果没有满足一定的要求,就不会引发阻塞,看到的结果就是SR和SU并没有互相阻塞。这个过程需要具体的去查看源码,此处不展开。

事务中的MDL锁在语句开始时申请,但并不会在语句结束后就马上释放,而是会等到事务结束时才进行释放

忙时对大表DDL会产生的灾难性的结果就是:如果后续对该表有查询操作,而且web端又有重试机制的话,那么会有一个新的session再次发起读请求,反复如此,线程池就会在短时间内爆炸

在线执行DDL的时候,需要检查一下information_schema.innodb_trx表中有没有当前操作表对应的事务,此外还可以使用ALTER TABLE tbl_name NOWAIT...进行操作(MySQL8.0新特性)

eg.

session1

select * from cpf where payid'xxx'

union

select * from cpf where payid'xxx'

union (union重复50次,确保查询时间几十秒以上)

session2

alter table cpf modify payer_userid varchar(500);

session3

select * from cpf where payer_userid='18051512003600300034';

#执行结果

session1执行了31秒,当session1完成的时候session2和session3相继完成

在session4中执行show processlist,结果如下

#变种1

如果session1在执行select之前,添加一句start transaction

会发现session1什么时候执行完commit,sesssion2和session3什么时候完成

也就是证实了在事务中的MDL锁,在语句查询完之后并不会释放,而是会随着事务的释放而释放

#变种2

session1和session3在执行select之前,添加一句start transaction,然后session1,2,3依次按顺序执行

会发现session1阻塞了session2,而session3在执行完start transaction之后就被阻塞,根本没有办法去执行后面的select

当session1执行commit释放之后,session2仍然处于阻塞状态,session3亦是如此

直到session2或者session3当中任意一个执行了停止(navicat客户端操作,类似于rollback)后,另一个才能完成执行

单纯从变种2的结果来看,MDL锁并没有按照执行时间的先后来进行分配,当session1的锁释放之后,session3先获得了读锁

MySQL是server-engine结构,MDL锁是server层的锁

通过show processlist可以发现waiting for table metadata lock,但这还远远不够,需要在performance_schema库中进行设置(MySQL8.0默认开启)

5.7临时开启

UPDATE performance_schema.setup_instruments SET ENABLED='YES', TIMED='YES' WHERE NAME='wait/lock/metadata/sql/mdl';

5.7永久开启(修改cnf配置)

[mysqld]

performance-schema-instrument = 'wait/lock/metadata/sql/mdl=ON'

global:全局级(FTWRL)

schema:库级(drop database)

table:表级(lock table read/write)

commit:提交级

关于global对象,主要作用是防止DDL和写操作的过程中,执行set golbal_read_only = on或flush tables with read lock。

关于commit对象锁,主要作用是执行flush tables with read lock后,防止已经开始在执行的写事务提交。insert/update/delete在提交时都会上(COMMIT,MDL_EXPLICIT,MDL_INTENTION_EXCLUSIVE)锁

DML和DDL在执行之前都会申请IX锁,DML会在global级别上加,而DDL会在global和schema这2个级别上都加IX(也就是2把锁)

IX与大部分锁都是兼容的,除了S,当然了X肯定是不兼容的;但IX与IX之间是兼容的,比如下图

flush table with read lock会持有这个锁(在global级别和commit级别)

FTWRL在全局级和事务级上分别加上了S锁

IX与S是不兼容的

所以DML和DDL都会与FTWRL产生阻塞

逻辑备份第一句:flush table with read lock(S锁)

大表DML(IX锁)

先执行的阻塞后执行的,逻辑备份之前需要检查是否有在线DDL(X锁)以及DML(IX锁),否则逻辑备份产生等待;尽量不要在忙时进行逻辑备份,否则阻碍忙时DML

如下图,前面2行是FTWRL持有的S锁,第3行是一个update语句,IX直接被阻塞,处于pending的锁等待状态;同时由于S锁的持有时间为EXPLICIT,表明FTWRL需要一个显示的释放(unlock tables)

DML并不是只有IX锁,DML和select .. for update在执行中持有的锁实际是SW锁(DML需要找一个大一点的表来验证,目前只验证了select .. for update),IX只是DML初期需要获得的锁

如下图是一个select for update语句,start transaction对应的是第2行的SR锁,而语句本身对应的是SW锁

如果在此时执行一个FTWRL,我们会发现2个会话并不会相互阻塞(因为S锁与SR和SW都是兼容的),如下图

但如果我们是先执行的FTWRL再执行的select for update,那么画风就不是像上图那样了

如下图所示,在先执行FTWRL的情况下,select for update压根没有获得SW锁,而是在获取IX锁的过程中就受挫了,一直处于pending状态。(如果这个S锁不释放,那么后面的IX会一直等待,直到超时)

S锁除了逻辑备份时的FTWRL以外,createa table as也会持有这个锁

目前已知的是desc操作会持有这个SH锁

SH锁与绝大部分锁都兼容,除开X锁

也就是说在做rename一类的操作的时候,你是无法去执行desc的

前面提到的start transaction,以及所有的非当前读都需要持有这个锁

非当前读的意思就是快照读,也就是普通的select

与SR锁有冲突的有2个,一个是X,另一个是SNRW

研发有时候会很困惑的问我,“我这个表只有几十行数据,select查不出来???”  这时候就需要检查MDL锁了

当前读需要持有此锁,常见的DML和select for update都对应此锁,但不包括DDL

与SW锁有冲突的有4个,SU,SRO,SNRW,X

看到一种说法是这个锁仅对MyISAM引擎生效,冲突范围与SW锁类似

部分alter语句会持有该锁。该锁可能会升级成SNW,SNRW,X;而X锁也有可能逐步降级到SU锁

SU锁和SU,SNW,SNRW,X锁互斥

表面看起来DML的SW锁和SU锁不互斥(DML和DDL),但实际上因为SU锁存在升级的属性,SU锁会升级到SNW锁,从而和SW产生互斥

如下图,SU并没有被SW锁阻塞,但升级到SNW之后,SNW被SW阻塞,一直处于pending状态

SU锁的兼容性如下

查看改过源码的例子,在执行alter的时候,SU会升级到X,之后X降级到SU,然后SU再升级到X

先SU,再SW,SW被SU阻塞

先SW,再SU,SU并未被SW阻塞,但是SU向上升级的过程中产生的SNW被SW阻塞;于是将SW的会话commit,之后SNW向下降级成SU,并成功获得锁;

所以虽然看起来SW和SU不是一个双向阻塞,但实际效果就是双向阻塞,无论DML和DDL谁在前面,都必然会发生相互的阻塞

不兼容的有点多,先贴一个兼容性

SU升级X的过程中会升级成SNW

SU升级成X的过程中,有一个copy的过程,这个过程就是SNW,在这个copy的过程中,允许DML但是不允许select(SR)

copy是一个非常耗时的过程

lock tables read的语句会持有这个锁

SRO阻塞SW,SNRW,X

兼容性如图

lock tables write的语句会持有这个锁

阻塞的锁非常多,除开SH和S以外,其他的都阻塞,连SR都阻塞了

兼容性如下

换句话说flush tables with read lock; (S)会堵塞lock table write; (SNRW)

但是flush tables with read lock;(S)却不会堵塞lock table read (SRO)

阻塞一切

各种DDL均属于这个范畴

create,drop,rename  (alter table add column也属于这个范畴)

SW锁阻塞X锁,(X锁是为了去执行一个drop)

X锁阻塞SH

thread104在做一个create table as的表复制操作,在表里面并没有发现X锁的信息,在thread95上对新表做一个desc操作,可以看到SH锁处于等待状态,然而这里阻碍SH的并不是X锁

只有1行的select被堵住

thread95做一个start transaction之后不提交,thread107对95的表做出一个rename操作,X锁被前面的SR锁阻塞,这时候thread108对该表发起一个limit仅仅为1的查询,但被X锁阻塞。由于lock_wait_timeout这个参数通常是1年,所以一连串查询被堵死

alter开头的几个SQL,无论是modify还是add,查询出来都是SU锁,但DDL是一个过程,其中的有一部分如果发生了阻塞,可能会发现是X锁阻塞;拿SR阻塞X锁的实验来说,SR阻塞X的过程非常短暂,如果没有刚好卡到那个点,看到的结果可能就是SR和SU互不干涉,但如果卡到那个点,就会观测到X被SR所阻塞。具体的需要读源码,这里不展开

SELECT

locked_schema,

locked_table,

locked_type,

waiting_processlist_id,

waiting_age,

waiting_query,

waiting_state,

blocking_processlist_id,

blocking_age,

substring_index(sql_text,"transaction_begin;" ,-1)ASblocking_query,

sql_kill_blocking_connection

FROM

(

SELECT

b.OWNER_THREAD_IDASgranted_thread_id,

a.OBJECT_SCHEMAASlocked_schema,

a.OBJECT_NAMEASlocked_table,

"Metadata Lock"ASlocked_type,

c.PROCESSLIST_IDASwaiting_processlist_id,

c.PROCESSLIST_TIMEASwaiting_age,

c.PROCESSLIST_INFOASwaiting_query,

c.PROCESSLIST_STATEASwaiting_state,

d.PROCESSLIST_IDASblocking_processlist_id,

d.PROCESSLIST_TIMEASblocking_age,

d.PROCESSLIST_INFOASblocking_query,

concat('KILL', d.PROCESSLIST_ID)ASsql_kill_blocking_connection

FROM

performance_schema.metadata_locks a

JOINperformance_schema.metadata_locks bONa.OBJECT_SCHEMA=b.OBJECT_SCHEMA

ANDa.OBJECT_NAME=b.OBJECT_NAME

ANDa.lock_status='PENDING'

ANDb.lock_status='GRANTED'

ANDa.OWNER_THREAD_IDb.OWNER_THREAD_ID

ANDa.lock_type='EXCLUSIVE'

JOINperformance_schema.threads cONa.OWNER_THREAD_ID=c.THREAD_ID

JOINperformance_schema.threads dONb.OWNER_THREAD_ID=d.THREAD_ID

) t1,

(

SELECT

thread_id,

group_concat(CASEWHENEVENT_NAME='statement/sql/begin'THEN"transaction_begin"ELSEsql_textENDORDERBYevent_id SEPARATOR ";" )ASsql_text

FROM

performance_schema.events_statements_history

GROUPBYthread_id

) t2

WHERE

t1.granted_thread_id=t2.thread_id

MDL锁处理

MDL元数据锁

快速处理MDL锁


本文名称:mysql怎么锁库,数据库锁表如何解锁 mysql
文章网址:http://cxhlcq.com/article/dsgsgpd.html

其他资讯

在线咨询

微信咨询

电话咨询

028-86922220(工作日)

18980820575(7×24)

提交需求

返回顶部