从数据库上的行锁定是否也适用于主数据库?

h5qlskok  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(324)

例如,在交易中,

START TRANSACTION;
SELECT count(*) as count FROM `order` WHERE user_id = 25286 LOCK IN SHARE MODE;
INSERT INTO `order` (`id`, `user_id`, `product_id`) VALUES (NULL, '25286', '36296');

我们执行 SELECT LOCK IN SHARE MODE; 这个 SELECT 查询将在从属数据库上执行并锁定一行。
是吗 SELECT LOCK IN SHARE MODE 还要在主数据库上创建行锁定,以便插入查询不会在主数据库上运行?

ogsagwnx

ogsagwnx1#

否-锁定不会渗透到整个服务器。因此,从服务器上的显式锁基本上不会锁定主服务器中相应的表,反之亦然。
我们在本例中使用的一个简单的解决方法是将所有这些特定的锁定查询只指向主服务器。因此,无论哪个客户端会话正在运行,这些查询总是只在主服务器上运行。这样就可以处理并发连接问题。
我在php代码中做了类似的过滤。为了将查询定向到相关服务器(将查询读取到从属服务器,将查询写入主服务器),编写了一个自定义函数来标识查询的类型。
值得注意的一点是,事务/锁定/解锁操作中的查询始终被视为写查询。
另外,对于 Set ,仅限 SET AUTOCOMMIT 以及 SET TRANSACTION 是写命令。
请在下面找到我们正在使用的实际代码的大致精简版本:

/*

* All the WRITE operation commands
* /

$write_commands = array(
    'create', 
    'alter', 
    'drop', 
    'truncate',
    'comment', 
    'rename', 
    'insert', 
    'update',
    'delete', 
    'merge', 
    'call', 
    'lock', 
    'unlock',
    'start', 
    'commit', 
    'rollback', 
    'savepoint',
    'set', 
    'replace' 
);

/*

* method to determine whether Read or Write
* @param $sql String (SQL query string)
* @return: void
* /

function determineReadOrWrite(string $sql): void {

    $dml_query = false;

    $words = str_word_count(strtolower(trim($sql)), 1);
    $first_word = isset($words[0]) ? $words[0] : '';
    $second_word = isset($words[1]) ? $words[1] : '';

    if (in_array($first_word, $this->write_commands)) {
        /* if it is not "set" then we set to master link */
        if ($first_word !== 'set'
        || ($first_word === 'set' && $second_word === 'autocommit')
        || ($first_word === 'set' && $second_word === 'transaction')
        ) {
            $dml_query = true;

            /* If we Lock tables or Begin a Transaction, we should run on Write servers only */
            /* till we Commit/Rollback or Unlock Tables */
            if(($first_word === 'start' && $second_word === 'transaction') 
            || $first_word === 'lock'){

                /* Set whether the current query is starting a Transaction / Lock etc */
                $this->wait_for_commit_rollback = true;
            }

            /* We are doing Commit/Rollback or Unlock Tables */
            if ($first_word === 'commit' 
            || $first_word === 'rollback' 
            || $first_word === 'unlock') {
                $this->wait_for_commit_rollback = false;
            }
        }
    }

    /* It's a insert/update/delete/etc query - to be run on Write Db only */
    if ($dml_query || $this->wait_for_commit_rollback) { 
        $this->setActiveConnectionToWrite(true);            

    } else {
        $this->setActiveConnectionToRead();
    }

}

相关问题