mysqli transaction/savepoint 函数与手动使用 query()
mysqli transaction/savepoint functions vs. manually using query()
下面两段代码的工作方式是否相同,或者本机 mysqli
交易函数是否做了一些额外的事情?
我对在启动和提交 transactions/creating 以及释放保存点时如何处理和报告错误(如果有的话)特别感兴趣。
使用特定的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
在我的示例中失败,则可能会引发此错误。在这种情况下,事务不会启动,因此 SAVEPOINT <name>
会被静默忽略,但 RELEASE SAVEPOINT <name>
随后会抛出错误。
让我感到奇怪的是,在这些情况下,以下行没有捕捉到创建初始事务的任何失败:
if (!$db->query($q)) {
throw new Exception($db->error);
}
...所以我不确定我是否正确。不幸的是,关于这些 mysqli 函数如何工作的官方 PHP 文档是 not very helpful.
基于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
。
下面两段代码的工作方式是否相同,或者本机 mysqli
交易函数是否做了一些额外的事情?
我对在启动和提交 transactions/creating 以及释放保存点时如何处理和报告错误(如果有的话)特别感兴趣。
使用特定的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
在我的示例中失败,则可能会引发此错误。在这种情况下,事务不会启动,因此 SAVEPOINT <name>
会被静默忽略,但 RELEASE SAVEPOINT <name>
随后会抛出错误。
让我感到奇怪的是,在这些情况下,以下行没有捕捉到创建初始事务的任何失败:
if (!$db->query($q)) {
throw new Exception($db->error);
}
...所以我不确定我是否正确。不幸的是,关于这些 mysqli 函数如何工作的官方 PHP 文档是 not very helpful.
基于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
。