簡體   English   中英

在PHP中鎖定MySQL INNODB行

[英]Locking a MySQL INNODB row in PHP

我有一個名為meta的表,具有兩個列namevalue

在一個由許多客戶端同時調用的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特權。

有關INNODB讀取鎖的MySQL文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM