Как протестировать транзакции MySQL?

У меня есть вопрос о тестировании запросов в транзакции. Я использовал транзакции MySQL в течение достаточно долгого времени теперь, и каждый раз я делаю это, я использую что-то как:

$doCommit = true;
$error = "";
mysql_query("BEGIN");

/* repeat this part with the different queries in the transaction
   this often involves updating of and inserting in multiple tables */
$query = "SELECT, UPDATE, INSERT, etc";
$result = mysql_query($query);
if(!$result){
    $error .= mysql_error() . " in " . $query . "<BR>";
    $doCommit = false;
}
/* end of repeating part */

if($doCommit){
    mysql_query("COMMIT");
} else {
    echo $error;
    mysql_query("ROLLBACK");
}

Теперь, это часто происходит, что я хочу протестировать свою транзакцию, таким образом, я изменяюсь mysql_query("COMMIT"); кому: mysql_query("ROLLBACK");, но я могу предположить, что это не очень хороший способ протестировать этот вид материала. Обычно не действительно выполнимо скопировать каждую таблицу в temp_table и обновить и вставить в те таблицы и удалить их впоследствии (например, потому что таблицы, возможно, очень большие). Конечно, когда код входит в производство, соответствующая обработка ошибок (вместо того, чтобы просто печатать ошибку) помещается в место.

Что лучший способ состоит в том, чтобы сделать материал как это?

13
задан rael_kid 10 August 2010 в 11:01
поделиться

3 ответа

Прежде всего, в вашей реализации есть ошибка. В случае ошибки запроса текущая транзакция автоматически откатывается, а затем закрывается. Таким образом, если вы продолжите выполнять запросы, они не будут входить в транзакцию (они будут зафиксированы в БД). Затем, когда вы выполните Откат , он автоматически завершится ошибкой. Из документации MySQL :

Rolling back can be a slow operation that may occur implicitly without the user 
having explicitly asked for it (for example, when an error occurs).

Явная команда ROLLBACK должна использоваться только в том случае, если вы определяете в приложении, что вам необходимо выполнить откат (по причинам, отличным от ошибки запроса). Например, если вы списываете средства со счета, вы явно откатываете, если обнаруживаете, что у пользователя недостаточно средств для завершения обмена ...

Что касается тестирования транзакций, я копирую база данных. Создаю новую базу данных и устанавливаю набор «фиктивных данных». Затем я запускаю все тесты с помощью автоматизированного инструмента. Инструмент фактически зафиксирует транзакции и принудительно откатит их, а также проверит, что ожидаемое состояние базы данных поддерживается на протяжении всех тестов. Поскольку сложнее программно узнать конечное состояние транзакции, если у вас есть неизвестные входные данные для транзакции, тестирование данных в реальном времени (или даже скопированных из живых) будет нелегким. Вы можете это сделать (и должны), но не полагайтесь на эти результаты при определении, работает ли ваша система. Используйте эти результаты для создания новых тестовых примеров для автоматического тестера ...

10
ответ дан 2 December 2019 в 00:17
поделиться

Обычно я использую что-то вроде (в моем примере я использую pdo):

$db->beginTransaction();
try {
  $db->exec('INSERT/DELETE/UPDATE');
  $db->commit();
}
catch (PDOException $e) {
  $db->rollBack();
  // rethrow the error or
}

Или, если у вас есть ваш собственный обработчик исключений, используйте специальное предложение для ваших PDOExceptions, где можно откатить выполнение. Пример:

function my_exception_handler($exception) {
  if($exception instanceof PDOException) {
    // assuming you have a registry class
    Registry::get('database')->rollBack();
  }
}
2
ответ дан 2 December 2019 в 00:17
поделиться

Может быть, вы могли бы рефакторить ваш первый пример и использовать какой-нибудь класс-обертку для доступа к БД?

В этом классе-обертке вы можете иметь переменную $normalCommit = true; и метод SetCommitMode(), который устанавливает эту переменную $normalCommit. И у вас есть метод Commit(), который выполняет коммит if($normalCommit == true). Или даже есть переменная $failTransaction, которая вызывает mysql_query("ROLLBACK"); если хотите (так вы можете пройти/не пройти много последовательных тестов).

Затем, когда вы запускаете тест, вы можете установить где-нибудь в файле кода теста: $myDBClass->SetCommitMode(false); или $myDBClass->RollBackNextOperation(true); перед операцией, которую вы хотите отменить, и она просто отменится. Таким образом, код, который вы тестируете, не будет содержать этих проверок отказа/коммита, их будет содержать только класс БД.

И обычно ТОЛЬКО тестовый код (особенно если вы проводите модульное тестирование) должен вызывать эти методы SetCommitMode и RollBackNextOperation, чтобы вы случайно не оставили эти вызовы в производственном коде.

Или вы можете передать в метод (если вы тестируете метод) какие-то безумные данные, например, отрицательные переменные для сохранения в UNSIGNED-полях, и тогда ваша транзакция должна отказать на 100%, если ваш код не сделает коммит после такой SQL-ошибки (но он не должен).

3
ответ дан 2 December 2019 в 00:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: