- 13, May 2024
- #1
Я просто наткнулся на интересную вещь, когда работал с вызовами PDO в своей текущей программе.
Соответствующая часть моей программы выполняет задачу удаления одной строки таблицы, зная два значения, составляющие первичный ключ таблицы.
(В этой конкретной таблице первичный ключ представляет собой комбинацию clientCode и orderNumber.
Как вы знаете, многостолбцовый первичный ключ означает, что комбинация столбцов в первичном ключе должна быть уникальной.
Поэтому я мог бы много заказов с одинаковым номером заказа или одним и тем же кодом клиента, но у меня может быть только ОДНА строка с заданной комбинацией clientCode и orderNumber.) Это означает, что мое удаление может удалить не более одной строки из таблицы, когда я удаляю через первичный ключ.
(Он также может не удалить какие-либо строки, если не существует строки, содержащей определенный clientCode и orderNumber.)
Я был очень удивлен, обнаружив, что следующий код позволит мне удалить данную строку НЕСКОЛЬКО раз! Правильно: вы можете удалить строку (и она исчезнет, как я убедился, напрямую запросив базу данных), а затем вы можете удалить ее снова, даже если она уже исчезла! Я просмотрел определение оператора выполнения PDO в руководстве по PHP, и там сказано, что он возвращает true, если он был успешным, и false, если он был неудачным.
В этом случае не должна ли неспособность удалить строку (поскольку ее там нет) считаться НЕУспешной? Я здесь, чтобы сообщить вам, что PHP считает мои повторные удаления одной и той же строки УСПЕШНЫМИ.
На мой взгляд, это противоречит всякой логике.
Кажется очень маловероятным, что PDO действительно может работать таким образом, поэтому я предполагаю, что каким-то образом сделал что-то, чтобы непреднамеренно заставить неудачи рассматриваться как успехи, но я действительно не знаю, что это будет.
Я надеюсь, что кто-то здесь может просветить меня. Я привожу полный пример кода, демонстрирующий проблему.
Все, что вам понадобится, это копия MySQL (или, возможно, подойдет другая база данных, если SQL совместим), а затем запустить эту программу. Если я не могу найти способ заставить PDO сказать мне правду о том, сработало ли удаление или нет, я полагаю, мне придется выполнить второй запрос, чтобы увидеть, действительно ли строка исчезла после удаления - и тогда надеюсь, что второй вопрос и мне не врет!
Вот два файла, которые вам понадобятся, чтобы попробовать это самостоятельно.
Соответствующая часть моей программы выполняет задачу удаления одной строки таблицы, зная два значения, составляющие первичный ключ таблицы.
(В этой конкретной таблице первичный ключ представляет собой комбинацию clientCode и orderNumber.
Как вы знаете, многостолбцовый первичный ключ означает, что комбинация столбцов в первичном ключе должна быть уникальной.
Поэтому я мог бы много заказов с одинаковым номером заказа или одним и тем же кодом клиента, но у меня может быть только ОДНА строка с заданной комбинацией clientCode и orderNumber.) Это означает, что мое удаление может удалить не более одной строки из таблицы, когда я удаляю через первичный ключ.
(Он также может не удалить какие-либо строки, если не существует строки, содержащей определенный clientCode и orderNumber.)
Я был очень удивлен, обнаружив, что следующий код позволит мне удалить данную строку НЕСКОЛЬКО раз! Правильно: вы можете удалить строку (и она исчезнет, как я убедился, напрямую запросив базу данных), а затем вы можете удалить ее снова, даже если она уже исчезла! Я просмотрел определение оператора выполнения PDO в руководстве по PHP, и там сказано, что он возвращает true, если он был успешным, и false, если он был неудачным.
В этом случае не должна ли неспособность удалить строку (поскольку ее там нет) считаться НЕУспешной? Я здесь, чтобы сообщить вам, что PHP считает мои повторные удаления одной и той же строки УСПЕШНЫМИ.
На мой взгляд, это противоречит всякой логике.
Кажется очень маловероятным, что PDO действительно может работать таким образом, поэтому я предполагаю, что каким-то образом сделал что-то, чтобы непреднамеренно заставить неудачи рассматриваться как успехи, но я действительно не знаю, что это будет.
Я надеюсь, что кто-то здесь может просветить меня. Я привожу полный пример кода, демонстрирующий проблему.
Все, что вам понадобится, это копия MySQL (или, возможно, подойдет другая база данных, если SQL совместим), а затем запустить эту программу. Если я не могу найти способ заставить PDO сказать мне правду о том, сработало ли удаление или нет, я полагаю, мне придется выполнить второй запрос, чтобы увидеть, действительно ли строка исчезла после удаления - и тогда надеюсь, что второй вопрос и мне не врет!
Вот два файла, которые вам понадобятся, чтобы попробовать это самостоятельно.
<?php
$debug = 0;
if ($debug) echo "Entering ".__FILE__."\n";
require_once dirname(__FILE__) . '/getPdoConnection.php';
//Get a database connection.
$pdo = getPDOConnection();
//Create the Heroes table.
if (createHeroesTable($pdo)) {
echo "Heroes table was successfully created.\n";
}
//Get contents of Heroes table to verify that it is empty.
$heroes = getHeroes($pdo);
echo "Heroes array:\n";
print_r($heroes);
//Create some heroes.
if (createHero($pdo, "Superman", "Kal-el", "5", "Justice League")) {
echo "Hero Superman was successfully inserted.\n";
}
if (createHero($pdo, "Robin", "Dick Grayson", "4", "Justice League")) {
echo "Hero Robin was successfully inserted.\n";
}
//Get contents of Heroes table to verify that the heroes were inserted.
$heroes = getHeroes($pdo);
echo "Heroes array:\n";
print_r($heroes);
//Determine the ID of a hero who needs to be updated.
$heroID = getHeroID($pdo, "Superman");
echo "The ID for Superman is: $heroID \n";
//Update the hero's information.
if (updateHero($pdo, $heroID, "Superman", "Clark Kent", "5", "Justice League")) {
echo "Superman's info was updated.\n";
}
//Get contents of Heroes table to verify that the update took place.
$heroes = getHeroes($pdo);
echo "Heroes array:\n";
print_r($heroes);
//Delete the hero which was just updated (Superman).
if (deleteHero($pdo, $heroID)) {
echo "Superman was deleted.\n";
}
//Delete the hero (Superman) *again*.
if (deleteHero($pdo, $heroID)) {
echo "Superman was deleted *again*.\n";
}
//Get contents of Heroes table to verify that the delete took place.
$heroes = getHeroes($pdo); //display the heroes table
echo "Heroes array:\n";
print_r($heroes);
//Delete all of the heroes.
if (deleteAllHeroes($pdo)) {
echo "All rows of the Heroes table were successfully deleted.\n";
}
//Drop the Heroes table.
if (dropHeroesTable($pdo)) {
echo "Heroes table was successfully dropped.\n";
}
exit;
function getHeroes($pdo) {
global $debug;
if ($debug) echo "Entering getHeroes()...\n";
//Fetch the heroes from the table. There is going to be at least one, otherwise we would have exited.
$sql = "select id, name, realname, rating, teamaffiliation from heroes";
$stmt = $pdo->query($sql);
$heroes = array(); //initialize heroes array which will hold the result set
while ($row = $stmt->fetch()) { //if the query returns no rows, the while loop will never start
// echo $row['id']."; ".$row['name']."; ".$row['realname']."; ".$row['rating']."; ".$row['teamaffiliation']."\n";
array_push($heroes, $row);
}
if ($debug) {
echo "heroes array:\n";
print_r($heroes);
}
return $heroes;
}
function getHeroID($pdo, $name) {
global $debug;
if ($debug) echo "Entering getHeroID($name)...\n";
$sql = "select id from heroes where name = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute(array($name));
//Find the id for the hero and return it. The user selected the row from a GUI
//and can only select a single existing hero at a time.
while ($row = $stmt->fetch()) {
$heroID = $row['id'];
}
return $heroID;
}
function createHero($pdo, $name, $realname, $rating, $teamaffiliation) {
global $debug;
if ($debug) echo "Entering createHeroes($name, $realname, $rating, $teamaffiliation)...\n";
$sql = "INSERT INTO heroes (name, realname, rating, teamaffiliation) values (?,?,?,?)";
$stmt = $pdo->prepare($sql);
if($stmt->execute(array($name, $realname, $rating, $teamaffiliation))) return true;
return false;
}
function updateHero($pdo, $id, $name, $realname, $rating, $teamaffiliation) {
global $debug;
if ($debug) echo "Entering updateHero($id)...\n";
$sql = "UPDATE heroes SET name=?, realname=?, rating=?, teamaffiliation=? WHERE id=?";
$stmt = $pdo->prepare($sql);
if($stmt->execute(array($name, $realname, $rating, $teamaffiliation, $id))) return true;
return false;
}
function deleteHero($pdo, $id) {
global $debug;
if ($debug) echo "Entering deleteHero($id)...\n";
$sql = "delete from heroes where id=?";
$stmt = $pdo->prepare($sql);
if($stmt->execute(array($id))) return true;
return false;
}
function deleteAllHeroes($pdo) {
global $debug;
if ($debug) echo "Entering deleteAllHeroes()...\n";
$sql = "delete from heroes";
$stmt = $pdo->prepare($sql);
if($stmt->execute()) return true;
return false;
}
function createHeroesTable($pdo) {
global $debug;
if ($debug) echo "Entering createHeroesTable()...\n";
$sql = "create table heroes (
id int(11) not null auto_increment,
name varchar(30) collate utf8_unicode_ci not null,
realname varchar(30) collate utf8_unicode_ci not null,
rating int(11) not null,
teamaffiliation varchar(30) collate utf8_unicode_ci not null,
primary key(id))";
$stmt = $pdo->prepare($sql);
if ($stmt->execute()) return true;
return false;
}
function dropHeroesTable($pdo) {
global $debug;
if ($debug) echo "Entering dropHeroesTable()...\n";
$sql = "drop table heroes";
$stmt = $pdo->prepare($sql);
if ($stmt->execute()) return true;
return false;
}
?>
PHP:
<?php function getPdoConnection() { $debug = 0; /* The values used to connect to the database are stored in an external ini file.
Read that * file and find the various values.
*/ $file = "TW.ini"; if (!$settings = parse_ini_file($file, TRUE)) throw new exception('Unable to open ' . $file . '.'); $driver = $settings['database']['driver']; $host = $settings['database']['host']; $port = $settings['database']['port']; $username = $settings['database']['username']; $password = $settings['database']['password']; $dbname = $settings['database']['dbname']; $charset = $settings['database']['charset']; if ($debug) { echo "driver: $driver\n"; echo "host: $host\n"; echo "port: $port\n"; echo "username: $username\n"; echo "password: $password\n"; echo "dbname: $dbname\n"; echo "charset: $charset\n"; } //Construct the DNS and options that are needed to connect to the database.
$dns = "$driver:host=$host;port=$port;dbname=$dbname;charset=$charset"; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; if ($debug) { echo "dns: $dns\n"; echo "options:\n"; print_r($options); } //Get a database connection.
$pdo = new PDO($dns, $username, $password, $options); return $pdo; } ?>
PHP: