关于locktableswrite的信息

http://www.itjxue.com  2023-01-22 22:26  来源:未知  点击次数: 

java程序中如何实现对mysql数据库中表的锁定

方法1:用mysql命令锁住表.

public?void?test()?{??

??

????String?sql?=?"lock?tables?aa1?write";??

????//?或String?sql?=?"lock?tables?aa1?read";???

????//?如果想锁多个表?lock?tables?aa1?read?,aa2?write?,?.....???

????String?sql1?=?"select?*?from?aa1?";??

??

????String?sql2?=?"unlock?tables";??

????try?{??

????????this.pstmt?=?conn.prepareStatement(sql);??

????????this.pstmt1?=?conn.prepareStatement(sql1);??

????????this.pstmt2?=?conn.prepareStatement(sql2);??

????????pstmt.executeQuery();??

????????pstmt1.executeQuery();??

????????pstmt2.executeQuery();??

??

????}?catch?(Exception?e)?{??

????????System.out.println("异常"?+?e.getMessage());??

????}??

??

}

对于read lock 和 write lock官方说明:

1.如果一个线程获得一个表的READ锁定,该线程(和所有其它线程)只能从该表中读取。

如果一个线程获得一个表的WRITE锁定,只有保持锁定的线程可以对表进行写入。

其它的线程被阻止,直到锁定被释放时为止。

2.当您使用LOCK TABLES时,您必须锁定您打算在查询中使用的所有的表。

虽然使用LOCKTABLES语句获得的锁定仍然有效,但是您不能访问没有被此语句锁定的任何的表。

同时,您不能在一次查询中多次使用一个已锁定的表——使用别名代替,

在此情况下,您必须分别获得对每个别名的锁定。

对与read lock 和 write lock个人说明:

1.read lock 和 write lock 是线程级(表级别).

2.在同一个会话中加了read lock锁. 只能对这个表进行读操作.对这个表以外的任何表都无法进行增、删、改、查的操作.

但是在不同会话中,只能对加了read lock的表进行读操作.但可以对read lock以外的表进行增、删、改、查的操作.

3.在同一个会话中加了write lock锁.只能对这个表进行读、写操作.对这个表以外的任何表都无法进行增、删、改、查的操作.

但是在不同会话中,无法对加了write lock的表进行读、写操作.但可以对write lock以外的表进行增、删、改、查的操作.

4.如果表中使用了别名.(SELECT * FROM aa1 AS byname_table)

在对aa1加锁时,必须把别名加上去(lock tables aa1 as byname_table read)

在同一个会话中.必须使用别名进行查询.

在不同的会话中.可以不需要使用别名进行查询.

5.在多个会话中可以对同一个表进行lock read操作.但不能在多个会话中对同一个表进行lock write操作(这些锁将等待已锁的表释放自身的线程锁)

如果多个会话对同一个表进行lock read操作.那么在这些会话中,也只能对以锁的表进行读操作.

6.如果要你锁住了一个表,需要嵌套查询.你必须使用别名,并且,要锁定别名.

例如.lock table aa1 read ,aa1 as byname_table read;

select * from aa1 where id in (select * from aa1 as xx??where id=2);

7.解锁必须用unlock tables;

另:

在JAVA程序中,要想解锁,需要调用 unlock tables来解锁.

如果没有调用unlock tables.

关闭connection 、程序结束 、调用GC 都能解锁.

方法2:用记录锁锁表.

public?void?test()?{??

??

????String?sql?=?"select?*?from?aa1?for?update";???

???????????????//?select?*?from?aa1?lock?in?share?mode;???

??

????try?{??

????????conn.setAutoCommit(false);??

????????this.pstmt?=?conn.prepareStatement(sql);??

????????pstmt.executeQuery();??

??

????}?catch?(Exception?e)?{??

????????System.out.println("异常"?+?e.getMessage());??

????}??

??

}

1.for update 与 lock in share mode 属于行级锁和页级锁

2.for update 排它锁,lock in share mode 共享锁

3.对于记录锁.必须开启事务.

4.行级锁定事实上是索引记录的锁定.只要是用索引扫描的行(或没索引全表扫描的行),都将被锁住.

5.在不同的隔离级别下还会使用next-key locking算法.即所扫描的行之间的“间隙”也会也锁住(在Repeatable read和Serializable隔离级别下有间隙锁).

6.在mysql中共享锁的含义是:在被共享锁锁住的行,即使内容被修改且并没有提交.在另一个会话中依然看到最新修改的信息.

在同一会话中加上了共享锁.可以对这个表以及这个表以外的所有表进行增、删、改、查的操作.

在不同的会话中.可以查到共享锁锁住行的最新消息.但是在Read Uncommitted隔离级别下不能对锁住的表进行删,

改操作.(需要等待锁释放才能操作...)

在Read Committed隔离级别下不能对锁住的表进行删,改操作.(需要等待锁释放才能操作...)

在Repeatable read隔离级别下不能对锁住行进行增、删、改操作.(需要等待锁释放才能操作...)

在Serializable隔离级别下不能对锁住行进行增、删、改操作.??(需要等待锁释放才能操作...)

7.在mysql中排他锁的含义是:在被排它锁锁住的行,内容修改并没提交,在另一个会话中不会看到最新修改的信息。

在不同的会话中.可以查到共享锁锁住行的最新消息.但是Read Uncommitted隔离级别下不能对锁住的表进行删,

改操作.(需要等待锁释放才能操作...)

在Read Committed隔离级别下不能对锁住的表进行删,改操作.(需要等待锁释放才能操作...)

在Repeatable read隔离级别下不能对锁住行进行增、删、改操作.(需要等待锁释放才能操作...)

在Serializable隔离级别下不能对锁住行进行增、删、改操作. (需要等待锁释放才能操作...)

8.在同一个会话中的可以叠加多个共享锁和排他锁.在多个会话中,需要等待锁的释放.

9.SQL中的update 与 for update是一样的原理.

10.等待超时的参数设置:innodb_lock_wait_timeout=50 (单位秒).

11.任何可以触发事务提交的命令,都可以关闭共享锁和排它锁.

MySQL 如何让unlock tables不隐式提交?

不加注释的写法:

public static int getMax(int [] arr)

{

int max =arr [0];

for (int x=1;xarr.length;x++ )

{

if (arr[x]max)

{

max =arr[x];

}

}

return max;

}

wordpress 数据库导入有问题,lock tables , 1044错误.

Navicat for MySQL 用这个试试,我都用这个导出导入,几百M的数据库 十几分钟就导入完成了,很好用

求教mysql的大神,mysql中建表时的语句LOCK TABLES WRITE有什么作用?

防止他人写入和读取你设定的表内容,只有被授权的用户能读取和写入

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锁

(责任编辑:IT教学网)

更多

推荐Flash actionscript文章