mysql中lock tables与unlock tables
官网:https://dev.mysql.com/doc/refman/5.0/en/lock-tables.html
LOCK TABLES
tbl_name
[[AS]alias
]lock_type
[,tbl_name
[[AS]alias
]lock_type
] ...lock_type
:
READ [LOCAL]
| [LOW_PRIORITY] WRITE UNLOCK TABLES
MySQL enables client sessions to acquire table locks explicitly for the purpose of cooperating with other sessions for access to tables, or to prevent other sessions from modifying tables during periods when a session requires exclusive access to them. A session can acquire or release locks only for itself. One session cannot acquire locks for another session or release locks held by another session.
Locks may be used to emulate transactions or to get more speed when updating tables. This is explained in more detail later in this section.
LOCK TABLES
explicitly acquires table locks for the current client session. Table locks can be acquired for base tables or (as of MySQL 5.0.6) views. You must have the LOCK TABLES
privilege, and the SELECT
privilege for each object to be locked.
。。。
线程A(命令行窗口A)
线程B(命令行窗口B)
1
mysql> lock tables user read;
2
mysql> select * from user;
mysql> select * from user;
3
mysql> insert into user values(12,'test');
其他线程:mysql> insert into user values(22,'2test');
4
mysql> unlock tables;
mysql> insert into user values(22,'ddd');
5
mysql> lock tables user read local;
mysql> insert into user values(2,'b');
6
mysql> update user set name = 'aaaaaaaaaaaaaaaaaaaaa' where id = 1;
线程A(命令行窗口A)
线程B(命令行窗口B)
1
mysql> lock tables user write;
2
mysql> select * from user;
mysql> select * from user;
3
mysql> unlock tables ;
4
mysql> select * from user;
-----------------------------
一篇文章:
mysql 的 表锁 lock tables 感觉就像一个 封闭的空间
mysql发现 lock tables 命令的时候,会将带有锁标记的表(table) 带入封闭空间,直到 出现 unlock tables 命令 或 线程结束, 才关闭封闭空间。
进入封闭空间时 , 仅仅只有锁标记的表(table) 可以在里面使用,其他表无法使用。
锁标记 分为 read 和 write 下面是 两种 锁的区别
--------------------------------------------------------------------
//如 将 table1 设为read锁, table2 设为write锁, table3 设为read锁
lock tables [table1] read,[table2] write,[table3] read;
----------------------------------------------------------------------
//执行到这里时,进入封闭空间。
1. table1 仅允许[所有人]读,[空间外]如需写、更新要等待[空间退出],[空间内]如需写、更新会引发mysql报错。
2. table2 仅允许[空间内]读写更新,[空间外]如需写、更新要等待[空间退出]。
3. table3 仅允许[所有人]读,[空间外]如需写、更新要等待[空间退出],[空间内]如需写、更新会引发mysql报错。
----------------------------------------------------------------------
//执行到这里时,退出封闭空间,释放所有表锁
unlock tables
----------------------------------------------------------------------
当前线程关闭时,自动退出封闭空间,释放所有表锁,无论有没有执行 unlock tables
上面一堆东西感觉很乱,下面我们看个实例吧。
在某个地方看到有个例子,具体描述类似如下:商店现在某商品只有1件库存,然后A与B在网上进行下订,A与B几乎同时(或许也就差几毫秒,A比B快那么一点点)进行。
很明显是只有A才能成功下单的,B则会收到库存不足的提示,但是作为放置在服务端的那个页面(或者称为脚本程序)我们得怎样去处理这个问题呢?或者我先放出一段代码吧。
$sql = "select number from goods where id=1";
$number = intval( $db->result( $db->query( $sql ), 0 ) );
if ( $number > 0 ) {
sleep( 2 );
$sql = "update goods set number=number-1 where id = 1";
if ( $db->query( $sql ) ) {
echo 'Ok!Here you are!';
} else {
echo 'Sorry!Something go wrong!Try it again.';
}
} else {
echo 'No more!you are so late!';
}
这部分代码除了缺少一定注释外都写得没错,当然$db是一个操作数据库的类,我只是将大部分方法封装了,这里的逻辑也是很明显了。
先获取id为1这个东东的库存数,看看是否为0,如果为0就订购不成功了,如果大于0则将库存减1然后提示ok。这确实没有任何错误,逻辑也对。如果请求是一个接一个地产生的,那么什么问题都没有,但当一些并发情况(paperen也不想用这种专业的名词,其实就是上面那个例子的情况,在相差不明显的时间内有多个请求产生)出现时就可能出现一些无厘头的问题了。你想啊,是不是可能存在一种情况,A刚发出请求,脚本处理到update之前B又发出请求,那么现在库存依然还有1,因为A的update还没有执行呢,所以$number不少于0,这次完了,B也下单了,于是库存变成-1了(假设原来只有1件),确实是一个荒谬而且比较搞笑的结果。
出现问题的原因很明显,就是忽略了这种并发情况的考虑,处理下订应该是种队列方式,也就是先来先得,就是说在执行这个下订动作是要排队的,前面的那个先下订然后后者才能下订,当然当后者下订前才再判断库存的数量。那么怎样解决这个问题呢,在程序层面上貌似真的没有方法去解决这个问题(paperen可没想到代码上的解决方案,有思路的可以留个言),所以在此才提到锁表的概念,你想啊,上面出现这个问题的归根于没有控制一个select number的先后顺序(或者可以这么说吧),因为在A执行update之前你又允许B去查询库存,当然结果还是1,至少要等待A更新库存后才允许其他人的任何操作,也就是对goods表进行一个排队操作,对goods表进行锁定。
说到这里,请不要以为锁表有多么高深,其实它就是一条sql
LOCK TABLE `table` [READ|WRITE]
解锁
UNLOCK TABLES;
引用专业的描述是
LOCK TABLES为当前线程锁定表。 UNLOCK TABLES释放被当前线程持有的任何锁。当线程发出另外一个LOCK TABLES时,或当服务器的连接被关闭时,当前线程锁定的所有表会自动被解锁。
如果一个线程获得在一个表上的一个READ锁,该线程和所有其他线程只能从表中读。 如果一个线程获得一个表上的一个WRITE锁,那么只有持锁的线程READ或WRITE表,其他线程被阻止。
已经是有种队列的味道,对不,所以解决方案很简单嘛,在select前加锁,执行完后面逻辑代码后解锁。或许有没有人会有一个疑问,就是如果万一锁表后线程就断掉了那么是不是就一直锁表了,这个确实是可能存在但是既然你想到了那么数据库的设计人员也一定考虑到了,可以告诉你关于unlock的一些资料:当线程发出另一个 LOCK TABLES,或当与服务器的连接被关闭时,被当前线程锁定的所有表将被自动地解锁。这下放心了吧。
好,看下改进后的代码。
$db->lock( 'goods', 2 );
$sql = "select number from goods where id=1";
$number = intval( $db->result( $db->query( $sql ), 0 ) );
if ( $number > 0 ) {
sleep( 2 );
$sql = "update goods set number=number-1 where id = 1";
if ( $db->query( $sql ) ) {
echo 'Ok!Here you are!';
} else {
echo 'Sorry!Something go wrong!Try it again.';
}
} else {
echo 'No more!you are so late!';
}
$db->unlock();
只加了两行代码,不过也不能这么说,因为paperen我修改了自己那个操作数据库的类,加了两个方法lock与unlock,其实这两个方法也很简单。
/**
* 锁表
* @param string $table 表名
* @param int $type 读锁1还是写锁2
*/
public function lock( $table, $type = 1 ) {
$type = ( $type == 1 ) ? 'READ' : 'WRITE';
$this->query( "LOCK TABLE `$table` $type" );
} /**
* 解锁
*/
public function unlock() {
$this->query( "UNLOCK TABLES" );
}
关于lock自己可以再斟酌一下,因为第二个参数这样弄看上去并不太舒服。嗯哼~那怎测试呢?paperen使用jmeter进行测试结果
关于jmeter可以在http://jakarta.apache.org/site/downloads/downloads_jmeter.cgi 这里下载,在邪恶的人手中可以是一个恐怖的工具在善良的人手中是一个友好的工具。
您需要创建两个线程,其实就是对服务器发出两个请求。
具体配置paperen在此不说,我导出了一个计划文件,大家可以试着打开就能看到paperen是怎测试的了。http://iamlze.cn/demo/locktable/locktable.jmx
保存下来然后导入必需调整一下你本地测试的路径,最后ctrl+R(运行),在线程下查看结果树就有请求的回应信息了。
首先测试不加锁表的情况(就是一开始不加lock与unlock操作的代码)看看两个线程出来的结果。
都是ok~~再看数据库
然后将number改回1,再将lock与unlock,锁表操作加上,再运行
好吧,数据表就不用看了吧,结果已经很明显了,再前一个请求对表操作完成之前,之后那些请求都要在等待,直到前面请求完成了才能操作,也就是队列的味道。
老实说mysql的事务也需要下点功夫研究一下,paperen关于锁表的了解也就是在查看事务的过程中产生的,在高级的应用过程中这种技术就更加重要,更加严谨的逻辑代码与严谨的数据库管理才能更进一步保证数据的真实与准确性。真是后知后觉。
mysql中lock tables与unlock tables的更多相关文章
- MySQL中lock tables和unlock tables浅析
MySQL中lock tables和unlock tables浅析 在MySQL中提供了锁定表(lock tables)和解锁表(unlock tables)的语法功能,ORACLE与SQL Se ...
- MySQL的lock tables和unlock tables的用法(转载)
早就听说lock tables和unlock tables这两个命令,从字面也大体知道,前者的作用是锁定表,后者的作用是解除锁定.但是具体如何用,怎么用,不太清楚.今天详细研究了下,总算搞明白了2者的 ...
- lock tables和unlock tables
1.lock tables table1 read,table2 read,table3 read igoodful@a8-apple-iphone-db00.wh(glc) > show ta ...
- LOCK TABLES和UNLOCK TABLES与Transactions的交互
LOCK TABLES对事务不安全,并且在试图锁定表之前隐式提交任何活动事务. UNLOCK TABLES只有在LOCK TABLES已经获取到表锁时,会隐式提交任何活动事务.对于下面的一组语句,UN ...
- 14.3.5 LOCK TABLES and UNLOCK TABLES Syntax
14.3.5 LOCK TABLES and UNLOCK TABLES Syntax LOCK TABLES tbl_name [[AS] alias] lock_type [, tbl_name ...
- LOCK TABLES 和 UNLOCK TABLES
MySQLdump的时LOCK TABLES 和 UNLOCK TABLES 在mysqldump后的数据中会发现有 LOCK TABLES tables_name WRITE;和结尾处有 UNLOC ...
- mysql中lock tables与unlock tables(锁表/解锁)使用总结
php mysql lock tables 使用有感 mysql 的 表锁 lock tables 感觉就像一个 封闭的空间 mysql发现 lock tables 命令的时候,会将带有锁标记的表(t ...
- MySQL LOCK TABLES 与UNLOCK TABLES
http://blog.csdn.net/zyz511919766/article/details/16342003 1语法 LOCK TABLES tbl_name[[AS] alias] lock ...
- MySQL中lock与latch的区分
这里要区分锁中容易令人混淆的概念lock与latch.在数据库中,lock与latch都可以成为锁,但两者有截然不同的含义 latch 一般称为闩锁(轻量级的锁) 因为其要求锁定的时间非常短,若迟勋时 ...
随机推荐
- MVC 无法将类型“System.Collections.Generic.List<AnonymousType#1>”隐式转换为“System.Collections.Generic.IList<Mvc3Modeltest.Models.Movie>”。存在一个显式转换(是否缺少强制转换?))
1.问题: 2.解决方案:强制指定类型. 解决之.
- java 新建文件夹保存
String Txtname = field.getText(); File file3 =new File("D:\\MATP_robot"+&qu ...
- [Angular 2] ng-class and Encapsulated Component Styles
import {Input, Component, View, NgClass} from "angular2/angular2"; @Component({ selector: ...
- TCP/IP之分层
网络协议通常分不同层次进行开发,每一层分别负责不同的通信功能.一个协议族,比方T C P / I P,是一组不同层次上的多个协议的组合.T C P / I P通常被觉得是一个四层协议系统. 1.每层的 ...
- Linux 开机自检的设置(tune2fs和fsck)
tune2fs和fsck的用法 tune2fs--调整ext2/ext3文件系统特性的工具. -l <device> 查看文件系统信息 -c <count> 设置强制自检的 ...
- jdbc插入修改clob类型的两种方式
方法一: Connection con = dbl.loadConnection(); strSql = "insert into table1(id,a) values (1,EMPTY_ ...
- Android(java)学习笔记243:多媒体之视频播放器
1.这里我们还是利用案例演示视频播放器的使用: (1)首先,我们看看布局文件activity_main.xml,如下: <RelativeLayout xmlns:android="h ...
- POJ 2653 Pick-up sticks (判断线段相交)
Pick-up sticks Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 10330 Accepted: 3833 D ...
- oracle中的function 、procedure、packages、package bodies比较
1 function和procedure的区别 1).可以理解函数是存储过程的一种 2).函数可以没有参数,但是一定需要一个返回值,存储过程可以没有参数,不需要返回值 3).函数return返回值没 ...
- Ext4.1 grid 多选(可无checkbox)
转载 在Ext4.1中的grid默认只能实现单选的. 如果你想要你的grid有多选功能,需要给grid增加selModel 如果你使用了Ext.create('Ext.selection.Checkb ...