mysql lock 锁表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql lock 锁表相关的知识,希望对你有一定的参考价值。

$sql1 = "LOCK TABLES `tests1`,`tests` READ";
$query1=mysql_query($sql1);
$sql2="select * from `tests` where `state`='0' order by id asc limit 0,1";
$query2=mysql_query($sql2);
$rs2=mysql_fetch_array($query2);
$sql5 = "update `tests` set `state`='1' where `id`='".$rs2['id']."'";
$query5=mysql_query($sql5);
$sql3="select * from `tests1` where `state`='0' order by id asc limit 0,1";
$query3=mysql_query($sql3);
$rs3=mysql_fetch_array($query3);
$sql6 = "update `tests1` set `state`='1' where `id`='".$rs3['id']."'";
$query6=mysql_query($sql6);
$sql4="insert into `tests2` (`name1`,`name2`,`time`) value('".$rs2['name']."','".$rs3['name']."','".time()."')";
$query4=mysql_query($sql4);
/*$fp = fopen("log.txt","a");//创建缓存
@fwrite($fp,$rs2['name']." ".$rs3['name']."\r\n");//写入文件
@fclose($fp);
sleep(1);*/
$sql7 = "UNLOCK TABLES";
$query=mysql_query($sql7);
如果短时间内执行多次的话 会查出重复的。。

参考技术A 在 MySQL 中,如果你显式的执行锁定语句(LOCK Tables ...)
那么你必须一次锁定在解锁之前需要访问的所有表,
而且,如果你以读锁定方式锁定的表,则不能对该表进行写操作,也就是说,你使用什么方式进行的锁定,就只能进行什么方式的操作

甚至如果你在 Query 语句中使用了别名,那么在之前的锁定中也必须使用别名
另外,虚机团上产品团购,超级便宜
参考技术B /*$fp = fopen("log.txt","a");//创建缓存
@fwrite($fp,$rs2['name']." ".$rs3['name']."\r\n");//写入文件
@fclose($fp);
sleep(1);*/
这里不能执行吗?追问

这个注释了 和 $sql4="insert into `tests2` (`name1`,`name2`,`time`) value('".$rs2['name']."','".$rs3['name']."','".time()."')";
这个一个效果 记录 $sql2 $sql3 查询出的值的

追答

参照
MySQL中不同的锁
# 内部表锁
# LOCK TABLES(运行在所有表类型上)
# GET_LOCK()/RELEASE_LOCK()
# 页锁(BDB表)
# ALTER TABLE在BDB表上也造成一个表锁
# LOCK TABLES 允许在一个表上的复合读操作或者一个写操作
# 通常写锁比读锁在禁止写操作的时候有更高的优先级.对写操作来说,可以使用LOW_PRIORITY关键字来使锁管理器优先进行读操作

UPDATE LOW_PRIORITY SET value=10 WHERE id=10;
读的优先级HIGH_PRIORITY

LOCK table tlb_name READ
flush status;
flush tables;
UNLOCK tables tlb_name

//LOCK TABLE tbl_name READ表示要锁定成只读状态,在这个状态下用户只能读取数据表,不能写入。
LOCK TABLE tbl_name WRITE则是更严格的锁定,用户不能读取也不能写入。

追问

不行额。 用 WRITE 重复的比 READ还多。

追答

那把UPDTE语句改了行不行
UPDATE LOW_PRIORITY

追问

还是很多重复的额。。。

追答

就是把你update `tests` set `state`='1' where `id`='".$rs2['id']改为
update LOW_PRIORITY `tests` set `state`='1' where `id`='".$rs2['id']
所有的UPdate都加LOW_PRIORITY子句看看。
另外:
在"LOCK TABLES `tests1`,`tests` READ"; 下面再加
flush tables;
先关闭所有打开的表,然后再作连接。

追问

不行额,。。。

追答

mysql_query("SET AUTOCOMMIT=0"); //设置事务不自动commit
$sql1 = "LOCK TABLES `tests1`,`tests` READ";
$query1=mysql_query($sql1);
$sql2="select * from `tests` where `state`='0' order by id asc limit 0,1";
$query2=mysql_query($sql2);
$rs2=mysql_fetch_array($query2);
$sql5 = "update `tests` set `state`='1' where `id`='".$rs2['id']."'";
mysql_query("COMMIT");//非autocommit模式,必须手动执行COMMIT使操作生效
$query5=mysql_query($sql5);
$sql3="select * from `tests1` where `state`='0' order by id asc limit 0,1";
$query3=mysql_query($sql3);
$rs3=mysql_fetch_array($query3);
$sql6 = "update `tests1` set `state`='1' where `id`='".$rs3['id']."'";
$query6=mysql_query($sql6);
if(mysql_num_rows==0)
mysql_query("ROLLBACK");//非autocommit模式,执行ROLLBACK使事务操作无效

mysql_query("SET AUTOCOMMIT=1");//恢复autocommit模式

$sql4="insert into `tests2` (`name1`,`name2`,`time`) value('".$rs2['name']."','".$rs3['name']."','".time()."')";
$query4=mysql_query($sql4);

$sql7 = "UNLOCK TABLES";
$query=mysql_query($sql7);

追问

还是不行 fsockopen 执行100次重复的就很多了

参考技术C 楼上正解 参考技术D 额 不明白你在搞什么?
你是想把你每次执行的命令保存到log里面去吗?
写一个存储过程吧
代码可读性好差

MySQL 8 锁表问题排查总结

第一步:查看锁表情况

执行如下指令:

show status like 'Table%'

核心指标说明:

Table_locks_immediate: 指的是能够立即获得表级锁的次数

Table_locks_waited: 指的是不能立即获取表级锁而需要等待的次数,如果数量大,说明锁等待多,有锁争用情况

第二步:正在被锁定的的表

执行如下指令:

show open TABLES where In_use > 0;

第三步:如果查看到锁争用情况严重,可以再查看当前执行的SQL

执行如下指令:

show processlist;

如果需要过滤用户/db/commond 等相关信息,也可以使用information_schema.processlist 表信息。

指令如下:

select * from information_schema.processlist;

也可以通过mysqladmin 指令打印processlist 进程信息。

执行如下指令:

root@241448b9f8d6:/# mysqladmin -uroot -p processlist
Enter password:
+----+-----------------+------------------+-------+---------+------+------------------------+------------------+
| Id | User            | Host             | db    | Command | Time | State                  | Info             |
+----+-----------------+------------------+-------+---------+------+------------------------+------------------+
| 5  | event_scheduler | localhost        |       | Daemon  | 8776 | Waiting on empty queue |                  |
| 55 | root            | 172.17.0.1:56330 | house | Sleep   | 1992 |                        |                  |
| 56 | root            | 172.17.0.1:56332 | house | Sleep   | 234  |                        |                  |
| 57 | root            | 172.17.0.1:56334 | house | Sleep   | 234  |                        |                  |
| 58 | root            | localhost        |       | Query   | 0    | init                   | show processlist |
+----+-----------------+------------------+-------+---------+------+------------------------+------------------+

mysqladmin命令有一个debug参数,可以分析当前MySQL服务的状态信息,同时也可以用来帮助我们定位当前锁的详细情况,这里我们通过该命令分析一下当前MySQL服务的详细状态,执行mysqladmin命令如下:

root@241448b9f8d6:/etc/mysql# mysqladmin -ujss -p -S /var/run/mysqld/mysqld.sock debug
Enter password:

拓展:

/var/run/mysqld/mysqld.sock: MySQL的配置文件my.cnf 查看Socker 文件目录地址

温馨提示: debug会将状态信息生成到mysql的错误文件,一般锁的信息都会保存在最后几行。

表锁文件展示:

hread database.table_name Locked/Waiting Lock_type
2 hdpic.t_wiki_zutu Waiting - write Highest priority write lock
123890 hdpic.t_wiki_zutu_category Locked - read Low priority read lock
123890 hdpic.t_wiki_zutu_photo Locked - read Low priority read lock
123890 hdpic.t_wiki_zutu Locked - read Low priority read lock
124906 hdpic.t_wiki_zutu Waiting - read Low priority read lock

从上述信息可以看出,123890持有的读锁阻塞了2的写入和124906的读操作,这个状态符合我们的推论,接下来处理就比较单纯了,如果现状不可接受,不能继续等待,将123890杀掉,释放资源即可:

执行如下指令:

mysql> kill 123890;

Query OK, 0 rows affected (0.00 sec)

以上是关于mysql lock 锁表的主要内容,如果未能解决你的问题,请参考以下文章

MySQL系列3 - 全局锁表锁行锁

oracle 表锁住了啥原因

mysql存储过程出现锁表锁行的情况怎么解决

查询mysql 哪些表正在被锁状态

怎么知道数据库表已经锁表了

关于PHP仲mysql和lock tables与unlock tables(锁表/解锁)使用第二篇