mysqli事务/保存点函数与手动使用query()

时间:2015-01-07 12:11:45

标签: php mysqli transactions mariadb

以下两段代码是否完全相同,或者本地mysqli事务函数是否会执行一些额外的操作?

我特别感兴趣的是在启动和提交事务/创建和释放保存点时如何处理和报告错误(如果有的话)。

使用特定的mysqli函数进行交易处理:

$db = new mysqli('localhost', 'root', 'batman', 'batcave');
if (!$db->begin_transaction()) { throw new Exception($db->error); }
exc_query('INSERT INTO utility_belt SET item="apple"');
exc_query('INSERT INTO utility_belt SET item="banana"');
if (!$db->savepoint('vegetables')) { throw new Exception($db->error); }
exc_query('INSERT INTO utility_belt SET item="potato"');
exc_query('DELETE FROM utility_belt WHERE item="turnip"');
if (!$db->release_savepoint('vegetables')) { throw new Exception($db->error); }
exc_query('INSERT INTO utility_belt SET item="orange"');
if (!$db->commit()) { throw new Exception($db->error); }

使用普通的旧query函数执行相同的操作:

$db = new mysqli('localhost', 'root', 'batman', 'batcave');
exc_query('START TRANSACTION');
exc_query('INSERT INTO utility_belt SET item="apple"');
exc_query('INSERT INTO utility_belt SET item="banana"');
exc_query('SAVEPOINT vegetables');
exc_query('INSERT INTO utility_belt SET item="potato"');
exc_query('DELETE FROM utility_belt WHERE item="turnip"');
exc_query('RELEASE SAVEPOINT vegetables');
exc_query('INSERT INTO utility_belt SET item="orange"');
exc_query('COMMIT');

上面使用的exc_query函数的实现:

function exc_query($q) {
    global $db;
    if (!$db->query($q)) {
        throw new Exception($db->error);
    }
}

我为什么要问?

我在尝试RELEASE SAVEPOINT <name>并看到SAVEPOINT <name> does not exist时偶尔会遇到问题,即使我确定我之前已将SAVEPOINT <name>发送到服务器。

根据我在MariaDB's documentation中读到的内容,如果我的示例中的初始START TRANSACTION失败,则可能会抛出此错误。在这种情况下,不会启动事务,因此会{x}忽略SAVEPOINT <name>,但RELEASE SAVEPOINT <name>会随后抛出错误。

让我想知道的是,在这些情况下,以下行没有捕获创建创建初始事务的任何失败:

if (!$db->query($q)) {
    throw new Exception($db->error);
}

......所以我不确定我是不对。不幸的是,关于mysqli函数如何工作的官方PHP文档是not very helpful

1 个答案:

答案 0 :(得分:0)

基于https://github.com/php/php-src/blob/master/ext/mysqli/mysqli_nonapi.c#L1115

static int mysqli_savepoint_libmysql(MYSQL * conn, const char * const name, zend_bool release)
{
    int ret;
    char * query;
    unsigned int query_len = spprintf(&query, 0, release? "RELEASE SAVEPOINT `%s`":"SAVEPOINT `%s`", name);
    ret = mysql_real_query(conn, query, query_len);
    efree(query);
    return ret;
}

PHP只是向数据库发送完全相同的查询,并没有其他任何内容。

至于为什么MySQLi::savepoint()MySQLi::query("SAVEPOINT")有任何不同,我不知道。 PHP源代码中的错误处理似乎是相同的,所以如果出现问题,我希望$db->query($q)的结果为false

相关问题