全局锁
顾名思义,全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是Flushtableswithreadlock(FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
表级锁
MySQL里面表级别的锁有两种:一种是表锁,一种是元数据锁(metadatalock,MDL)。
表锁
表锁的语法是locktablesread/write。与FTWRL类似,可以用unlocktables主动释放锁,也可以在客户端断开的时候自动释放。需要注意,locktables语法除了会限制别的线程的读写外,也限定了本线程接下来的 *** 作对象。
元数据锁
MDL不需要显式使用,在访问一个表的时候会被自动加上。MDL的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。
1\x0d\如何锁一个表的某一行\x0d\\x0d\SETTRANSACTION\x0d\ISOLATIONLEVELREADUNCOMMITTED\x0d\\x0d\SELECTFROMtableROWLOCKWHEREid=1\x0d\\x0d\2锁定数据库的一个表\x0d\\x0d\SELECTFROMtableWITH(HOLDLOCK)\x0d\\x0d\加锁语句:\x0d\sybase:\x0d\update表setcol1=col1where1=0\x0d\;\x0d\MSSQL:\x0d\selectcol1from表(tablockx)\x0d\where\x0d\1=0\x0d\;\x0d\oracle:\x0d\LOCKTABLE表INEXCLUSIVEMODE;\x0d\\x0d\加锁后其它人不可 *** 作,直到加锁用户解锁,用commit或rollback解锁\x0d\\x0d\几个例子帮助大家加深印象\x0d\\x0d\设table1(A,B,C)\x0d\ABC\x0d\a1b1c1\x0d\a2b2c2\x0d\a3b3c3\x0d\\x0d\1)排它锁\x0d\新建两个连接\x0d\在第一个连接中执行以下语句\x0d\begintran\x0d\updatetable1\x0d\\x0d\set\x0d\A='aa'\x0d\whereB='b2'\x0d\waitfordelay\x0d\'00:00:30'--等待30秒\x0d\committran\x0d\\x0d\在第二个连接中执行以下语句\x0d\begintran\x0d\selectfromtable1\x0d\\x0d\whereB='b2'\x0d\committran\x0d\\x0d\若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒\x0d\\x0d\2)共享锁\x0d\在第一个连接中执行以下语句\x0d\begintran\x0d\selectfromtable1\x0d\holdlock\x0d\-holdlock人为加锁\x0d\whereB='b2'\x0d\waitfordelay\x0d\'00:00:30'--等待30秒\x0d\committran\x0d\\x0d\在第二个连接中执行以下语句\x0d\begintran\x0d\selectA,C\x0d\from\x0d\table1\x0d\whereB='b2'\x0d\updatetable1\x0d\\x0d\set\x0d\A='aa'\x0d\whereB='b2'\x0d\committran\x0d\\x0d\若同时执行上述两个语句,则第二个连接中的select查询可以执行\x0d\而update必须等待第一个事务释放共享锁转为排它锁后才能执行\x0d\即要等待30秒\x0d\\x0d\3)死锁\x0d\增设table2(D,E)\x0d\DE\x0d\d1e1\x0d\d2e2\x0d\\x0d\在第一个连接中执行以下语句\x0d\begintran\x0d\updatetable1\x0d\\x0d\set\x0d\A='aa'\x0d\whereB='b2'\x0d\waitfordelay\x0d\'00:00:30'\x0d\updatetable2\x0d\\x0d\set\x0d\D='d5'\x0d\whereE='e1'\x0d\committran\x0d\\x0d\在第二个连接中执行以下语句\x0d\begintran\x0d\updatetable2\x0d\\x0d\set\x0d\D='d5'\x0d\whereE='e1'\x0d\waitfordelay\x0d\'00:00:10'\x0d\updatetable1\x0d\\x0d\set\x0d\A='aa'\x0d\whereB='b2'\x0d\committran\x0d\\x0d\同时执行,系统会检测出死锁,并中止进程\x0d\\x0d\补充一点:\x0d\SqlServer2000支持的表级锁定提示\x0d\\x0d\HOLDLOCK持有共享锁,直到整个事务完成,应该在被锁对象不需要时立即释放,等于SERIALIZABLE事务隔离级别\x0d\\x0d\NOLOCK语句执行时不发出共享锁,允许脏读,等于READ\x0d\UNCOMMITTED事务隔离级别\x0d\\x0d\PAGLOCK在使用一个表锁的地方用多个页锁\x0d\\x0d\READPAST让sql\x0d\server跳过任何锁定行,执行事务,适用于READUNCOMMITTED事务隔离级别只跳过RID锁,不跳过页,区域和表锁\x0d\\x0d\ROWLOCK\x0d\强制使用行锁\x0d\\x0d\TABLOCKX强制使用独占表级锁,这个锁在事务期间阻止任何其他事务使用这个表\x0d\\x0d\UPLOCK\x0d\强制在读表时使用更新而不用共享锁\x0d\\x0d\应用程序锁:\x0d\应用程序锁就是客户端代码生成的锁,而不是sqlserver本身生成的锁\x0d\\x0d\处理应用程序锁的两个过程\x0d\\x0d\sp_getapplock锁定应用程序资源\x0d\\x0d\sp_releaseapplock\x0d\为应用程序资源解锁\x0d\\x0d\注意:锁定数据库的一个表的区别\x0d\\x0d\SELECTFROMtableWITH(HOLDLOCK)\x0d\其他事务可以读取表,但不能更新删除\x0d\\x0d\SELECTFROMtableWITH(TABLOCKX)\x0d\其他事务不能读取表,更新和删除\x0d\\x0d\1\x0d\如何锁一个表的某一行\x0d\/\x0d\测试环境:windows2Kserver+Mssql2000\x0d\\x0d\所有功能都进行测试过,并有相应的结果集,如果有什么疑义在论坛跟帖\x0d\\x0d\关于版权的说明:部分资料来自互联网,如有不当请联系版主,版主会在第一时间处理。\x0d\\x0d\功能:sql遍历文件夹下的文本文件名,当然你修改部分代码后可以完成各种文件的列表。\x0d\/\x0d\\x0d\A\x0d\连接中执行\x0d\\x0d\SETTRANSACTION\x0d\ISOLATIONLEVELREPEATABLE\x0d\READ\x0d\\x0d\begintran\x0d\\x0d\selectfromtablename\x0d\with\x0d\(rowlock)whereid=3\x0d\\x0d\waitfordelay'00:00:05'\x0d\\x0d\committran\x0d\\x0d\B连接中如果执行\x0d\\x0d\updatetablenameset\x0d\colname='10'whereid=3\x0d\--则要等待5秒\x0d\\x0d\updatetablename\x0d\set\x0d\colname='10'whereid3\x0d\--可立即执行\x0d\\x0d\2\x0d\锁定数据库的一个表\x0d\\x0d\SELECTFROMtableWITH(HOLDLOCK)\x0d\\x0d\注意:锁定数据库的一个表的区别\x0d\\x0d\SELECTFROMtableWITH(HOLDLOCK)\x0d\\x0d\其他事务可以读取表,但不能更新删除\x0d\\x0d\SELECTFROMtableWITH(TABLOCKX)\x0d\\x0d\其他事务不能读取表,更新和删除
方法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 {
thispstmt = connprepareStatement(sql);
thispstmt1 = connprepareStatement(sql1);
thispstmt2 = connprepareStatement(sql2);
pstmtexecuteQuery();
pstmt1executeQuery();
pstmt2executeQuery();
} catch (Exception e) {
Systemoutprintln("异常" + egetMessage());
}
}
对于read lock 和 write lock官方说明:
1如果一个线程获得一个表的READ锁定,该线程(和所有其它线程)只能从该表中读取。
如果一个线程获得一个表的WRITE锁定,只有保持锁定的线程可以对表进行写入。
其它的线程被阻止,直到锁定被释放时为止。
2当您使用LOCK TABLES时,您必须锁定您打算在查询中使用的所有的表。
虽然使用LOCKTABLES语句获得的锁定仍然有效,但是您不能访问没有被此语句锁定的任何的表。
同时,您不能在一次查询中多次使用一个已锁定的表——使用别名代替,
在此情况下,您必须分别获得对每个别名的锁定。
对与read lock 和 write lock个人说明:
1read 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 {
connsetAutoCommit(false);
thispstmt = connprepareStatement(sql);
pstmtexecuteQuery();
} catch (Exception e) {
Systemoutprintln("异常" + egetMessage());
}
}
1for update 与 lock in share mode 属于行级锁和页级锁
2for 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在同一个会话中的可以叠加多个共享锁和排他锁在多个会话中,需要等待锁的释放
9SQL中的update 与 for update是一样的原理
10等待超时的参数设置:innodb_lock_wait_timeout=50 (单位秒)
11任何可以触发事务提交的命令,都可以关闭共享锁和排它锁
以上就是关于mysql中锁的类型有哪些(mysql的锁有几种)全部的内容,包括:mysql中锁的类型有哪些(mysql的锁有几种)、如何对“行、表、数据库”加锁、java程序中如何实现对mysql数据库中表的锁定等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)