![](/img/trans.png)
[英]MySQL Update query - Will the 'where' condition respected on race condition and row locking? (php, PDO, MySQL, InnoDB)
[英]Locking a MySQL INNODB row in PHP
我有一個名為meta
的表,具有兩個列name
和value
。
在一個由許多客戶端同時調用的php腳本中,我這樣做:-
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan') LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
或這個:-
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan' <b>FOR UPDATE</b>) LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
不幸的是,由於客戶端最終使用重復的id
,因此這似乎不起作用。 數據庫負載很重, SELECT
花費了幾秒鍾。
$mysqli->autocommit(FALSE);
$mysqli->query("BEGIN;");
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan' FOR UPDATE) LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
$mysqli->commit();
這是一個復雜的問題; 鎖定和事務級別,但是上面的魔力是BEGIN
語句。 沒有它,每個語句都將在其自己的事務級別上運行,並且FOR UPDATE
鎖被過早地解鎖。
請先嘗試以下實驗,然后再根據您的要求進行映射。
創建表:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`notid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
然后創建:
創建rowlocking.php
<?php
require_once('connectvars.php');
// Connect to the database
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$query = "START TRANSACTION";
$data = mysqli_query($dbc, $query);
$query = "SELECT * FROM t1 WHERE id=5 FOR UPDATE";
$data = mysqli_query($dbc, $query);
if (mysqli_num_rows($data) != 0) {
$row = mysqli_fetch_array($data);
echo $row['id'];
echo $row['notid'];
}
//$query = "COMMIT";
//$data = mysqli_query($dbc, $query);
sleep(10);
echo "After 10 seconds";
?>
上面的腳本將訪問id = 5的行,並鎖定其他事務,直到休眠時間10秒。
創建rowlocking1.php
<?php
require_once('connectvars.php');
// Connect to the database
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$query = "START TRANSACTION";
$data = mysqli_query($dbc, $query);
$query = "SELECT * FROM t1 WHERE id=5 FOR UPDATE";
$data = mysqli_query($dbc, $query);
if (mysqli_num_rows($data) != 0) {
$row = mysqli_fetch_array($data);
echo $row['id'];
echo $row['notid'];
}
//sleep(10);
//$query = "COMMIT";
//$data = mysqli_query($dbc, $query);
//echo "After 10 seconds";
?>
上面的腳本嘗試訪問ID = 5的同一行。
現在,如果您運行腳本進行行鎖定,並且在10秒鍾的睡眠時間內運行rowlocking1,它將無法訪問行id = 5,直到通過行鎖定將其釋放。 一旦經過行鎖定的10秒鍾睡眠時間,便可以訪問id = 5的行。
嘗試用您的腳本映射此概念,您將獲得innoDB行級鎖定。 如果需要詳細說明,請發表評論。
這是你想要的?
query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan' LOCK IN SHARE MODE) LIMIT 1000 LOCK IN SHARE MODE;
UPDATE meta SET value=value+1000 WHERE name='scan';");
我不確定這是否是您要查找的內容,但是如果是這樣,請記住在必要時/之后在必要時對表進行解鎖,並確保您使用的帳戶具有LOCK特權。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.