У меня есть две таблицы, связанные внешним ключом.
Чтобы зарегистрировать пользователя, я хочу последовательно вставить его информацию в информационную таблицу и учетные данные в таблицу доступа.
Но когда вторая вставка не удалась (по какой-либо причине), я хотел бы отменить (удалить) первую.
Вот часть кода:
// Data going to table "info"
$info = array(
"fname" => $_POST["fname"],
"lname"=> $_POST["lname"]
);
// if insert into table "info" is successfull
if ($lastInsertID = $this->model->addUser("info", $info)) {
// Data going to table "access"
$access = array(
"id" => $lastInsertID,
"password" => $_POST["password"],
"group" => "users",
"privilege" => 0,
);
// insert into table "access"
if ($this->model->addUser("access", $access)) {
echo json_encode(array("success"));
}
else {
// if insert into table "access" fails
// remove the last insert into table "info"
$this->model->deleteUser("info", $lastInsertID);
echo json_encode(array("error", "access"));
}
}
else echo json_encode(array("error", "info"));
Проблема в том, что если вторая вставка (в таблицу «доступ») завершается неудачей, код удаления последней вставки в таблицу «информация» не выполняется. Взамен я получаю только исключение SQLSTATE и единственная строка в таблице «информация» остается
Как я могу улучшить свой код? Или есть ли лучший способ обработки «последовательной вставки» с помощью php и postgresql?
Спасибо, Алекс. Я признаю, что я новичок в postgresql (я знаю только действия CRUD, но не слишком много). Но я углублюсь в это, чтобы увидеть.
Это не специально для PostgreSQL, транзакции поддерживает практически любая база данных.
Понял @FrankHeikens! Я нашел то, что мне нужно, на странице postgresqltutorial.com/postgresql-php/transaction.
Можете ли вы также показать нам свой метод addUser()?
Используйте транзакцию:
Вы можете начать ТРАНЗАКТОИН. Затем выполните addUser().
если ваши действия успешны, зафиксируйте их, в противном случае откатите.
Добавьте несколько простых методов-оболочек в класс модели:
// I don't know your names (class name, variable names, ...), So I use sample names
class DataModel {
/* your current code */
public function beginTransaction()
{ $this->db_connection->beginTransaction(); }
public function commit()
{ $this->db_connection->commit(); }
public function rollBack()
{ $this->db_connection->rollBack(); }
}
Теперь вызовите методы транзакции в своем коде:
// Begin a transaction
$this->model->beginTransaction(); // <=====
// Data going to table "info"
$info = array(
"fname" => $_POST["fname"],
"lname"=> $_POST["lname"]
);
// if insert into table "info" is successfull
if ($lastInsertID = $this->model->addUser("info", $info)) {
// Data going to table "access"
$access = array(
"id" => $lastInsertID,
"password" => $_POST["password"],
"group" => "users",
"privilege" => 0,
);
// insert into table "access"
if ($this->model->addUser("access", $access)) {
// Commit changes; Write changes to database actually.
$this->model->commit(); // <=====
echo json_encode(array("success"));
}
else {
// if insert into table "access" fails
// RollBack; Cancel all changes you make in your transaction.
$this->model->rollBack(); // <=====enter code here
echo json_encode(array("error", "access"));
}
}
else echo json_encode(array("error", "info"));
Примерно это я и сделал. Я обернул транзакцию в try-catch вместо if-else, как вы. Но это сработало. Очень полезно @safineh. Спасибо !
Если приведенный выше ответ решил вашу проблему или привел вас к решению, пожалуйста, примите его. Это поможет будущим пользователям столкнуться с такой же или похожей проблемой и удалит ее из очереди без ответа. Пожалуйста, не оставляйте успешно ответивший вопрос без ответа.
Привет @Belayer. Не знал об этом правиле сообщества (потому что новичок). Но уверяю вас, мне не лень быть благодарным или полезным. Спасибо за ваше предложение.
Поймите, это тоже процесс обучения.
Читайте о транзакциях.