Основы PHP
  Что такое PHP?
  Возможности PHP
  Преимущества PHP
  История развития
  Что нового в PHP5?
  «Движок» PHP
  Переход на PHP 5.3
New Переход на PHP 5.6
  Введение в PHP
  Изучение PHP
  Основы CGI
  Синтаксис PHP
  Типы данных PHP
  Переменные в PHP
  Константы PHP
  Выражения PHP
  Операторы PHP
  Конструкции PHP
  Ссылки в PHP
  PHP и ООП
  Безопасность
  Функции PHP
  Функции по категориям
  Функции по алфавиту
  Стандартные функции
  Пользовательские
  PHP и HTTP
  Работа с формами
  PHP и Upload
  PHP и Cookies
  PHP и базы данных
  PHP и MySQL
  Документация MySQL
  Учебники
  Учебники по PHP
  Учебники по MySQL
  Другие учебники
  Уроки PHP
  Введение
  Самые основы
  Управление
  Функции
  Документация
  Математика
  Файлы
  Основы SQL
  Дата и время
  CURL
  Изображения
  Стили
  Безопасность
  Установка
  Проектирование БД
  Регулярные выражения
  Подготовка к работе
  Быстрый старт
  Установка PHP
  Установка MySQL
  Конфигурация PHP
  Download / Скачать
  Скачать Apache
  Скачать PHP
  Скачать PECL
  Скачать PEAR
  Скачать MySQL
  Редакторы PHP
  Полезные утилиты
  Документация
  PHP скрипты
  Скачать скрипты
  Инструменты
  PHP в примерах
  Новости портала
 Главная   »  Сборник статей
 
 

Транзакции в PostgreSQL версии 8.0

Автор: Джошуа Д. Дрейк

Несомненно, транзакции очень хороши, но транзакции в предыдущих версиях PostgreSQL пропагандировали лозунг – “все, или ничего”, останавливая транзакцию, если ошибка произошла в ее пределах. К счастью, новая версия PostgreSQL 8 позволяет взглянуть на это подругому, добавляя “savepoints” (точки сохранения), позволяя откатить назад только часть транзакции и восстановиться от ошибки изящно.

Одна из очень хороших особенностей PostgreSQL – транзакции. Они предотвращают случайную потерю данных или их искажение.

Например, скажем, вы хотите удалить записи в таблице. В PostgreSQL команда выглядит так:

template1=# DELETE FROM foo;

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

BEGIN;

DELETE FROM foo;

DELETE 50

Параметр BEGIN заставляет базу начать транзакцию. Поскольку, скоро вы понимаете, что забыли включить параметр WHERE, и удалили все столбцы, то вам необходимо будет сделать обратную перемотку и восстановить данные:

BEGIN;

DELETE FROM foo;

DELETE 50

ROLLBACK;

Есть один недостаток в такой реализации транзакций – если внутри транзакции произошла ошибка, вы вынуждены сделать перемотку. Команда перемотки должна будет выполнена в пределах транзакции, до того, как произведены какие-либо команды в пределах соединения. Как только перемотка будет выполнена, вы должны будете повторить действия снова в том виде, который не будет вызывать ошибку. Это правило включает в себя и ошибки пользователей: типа удаления всех отчетов в таблице; синтаксические ошибки: типа попытки выбрать из столбца, который не существует. Например:

BEGIN;

UPDATE foo SET bar = (SELECT count(*) FROM baz));

INSERT INTO foo (column1) SELECT column2 FROM bar;

ОШИБКА: отношение "bar" не существует

CREATE TABLE bar (column1 text, column2 float);

ОШИБКА: текущая транзакция прервана

команды, игнорируемые до конца блока

Из-за ошибки вы будете делать перемотку и вся ваша текущая работа будет потеряна. Этот специфический момент транзакций PostgreSQL особенно раздражает в период отладки и тестирования.

Точки сохранения – путь к спасению

Новая версия PostgreSQL 8 обращается к этой проблеме с помощью точек сохранения - 'savepoints'. Точки сохранения - это именованные метки, которые разбивают транзакцию на этапы, заставляя базу сохранять данные в рамках каждого этапа. В случае ошибки, мы можем определить этап на котором она возникла, и сделать перемотку только до предыдущей точки сохранения, не теряя при этом работу, которая лежит перед savepoint с ошибкой. Поскольку кажная savepoint имеет свое имя, то и обращаться к ней необходимо по ее имени.

Чтобы инициализировать savepoint, вы должны быть в пределах операционного блока:

template1=# BEGIN;

BEGIN

template1=# INSERT INTO foo(column1,column2,column3) VALUES (1,2,0);

INSERT 17231 1

template1=# INSERT INTO foo(column1,column2,column3) VALUES (1,2,0);

INSERT 17232 1

template1=# INSERT INTO foo(column1,column2,column3) VALUES (1,2,0);

INSERT 17233 1

template1=# SELECT * FROM foo;

column1 | column2 | column3

--------+---------+--------

    1   |   2     |   0  

    1   |   2     |   0

    1   |   2     |   0

(3 rows)

template1=# SAVEPOINT main_values_inserted;

SAVEPOINT

template1=# INSERT INTO foo(column1,column2,column3) VALUES (1,2,1/0);

ОШИБКА: деление на ноль

ОШИБКА: деление на ноль

В предыдущей версии PostgreSQL, вы потеряли бы все INSERT данные в предыдущем коде (после возникновения ошибки деления на ноль в последнем утверждении INSERT), но в версии 8 вы можете сделать перемотку до определенного savepoint. Обратите внимание, что код содержит savepoint с именем 'main_values_inserted'. Для обратной перемотки до этой savepoint вы можете написать:

template1=# ROLLBACK TO main_values_inserted;

ROLLBACK

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

template1=# INSERT INTO foo(column1,column2,column3) VALUES (5,9,10);

INSERT 17234 1

template1=# INSERT INTO foo(column1,column2,column3) VALUES (5,9,10);

INSERT 17235 1

template1=# INSERT INTO foo(column1,column2,column3) VALUES (5,9,10);

INSERT 17236 1

template1=# INSERT INTO foo(column1,column2,column3) VALUES (5,9,10);

INSERT 17237 1

template1=# SAVEPOINT secondary_values_inserted;

SAVEPOINT

template1=# SELECT * FROM foo;

column1 | column2 | column3

--------+---------+--------

   1    |    2    |   0

   1    |    2    |   0

   1    |    2    |   0

   5    |    9    |   10

   5    |    9    |   10

   5    |    9    |   10

   5    |    9    |   10

(7 rows)

template1=# SAVEPOINT all_values_inserted;

SAVEPOINT

template1=# DELETE FROM foo;

DELETE 7

template1=# SELECT * FROM foo;

column1 | column2 | column3

---------+--------+--------

(0 rows)

Ой. Также, как и в первом примере этой статьи, вы фактически хотели удалить только одну строку где 'column = 1'. Но вы можете сделать перемотку ко второй savepoint 'all_values_inserted' в коде выше.

template1=# ROLLBACK TO all_values_inserted;

ROLLBACK

template1=# SELECT * FROM foo;

column1 | column2 | column3

--------+---------+--------

   1    |    2    |    0

   1    |    2    |    0

   1    |    2    |    0

   5    |    9    |    10

   5    |    9    |    10

   5    |    9    |    10

   5    |    9    |    10

(7 rows)

Обратите внимание, это восстановило все ваши данные. Теперь вы можете запустить корректные команды для удаления.

template1=# DELETE FROM foo WHERE column1 = 1;

DELETE 3

template1=# SELECT * FROM foo;

column1 | column2 | column3

--------+---------+--------

   5    |    9    |    10

   5    |    9    |    10

   5    |    9    |    10

   5    |    9    |    10

(4 rows)

Наконец, вы можете завершить вашу транзакцию. Последняя команда SELECT показывает, что целостность данных после всех этих вставок и обратных перемоток не повреждена.

template1=# COMMIT;

COMMIT

template1=# select * from foo;

column1 | column2 | column3

--------+---------+--------

   5    |    9    |    10

   5    |    9    |    10

   5    |    9    |    10

   5    |    9    |    10

(4 rows)

Джошуа Д. Дрейк – Президент Command Prompt, Inc. Компания занимается поддержкой PostgreSQL программированием. Он также соавтор 'Практического PostgreSQL' от издательства O'reilly и Партнеров.

Оригинал на http://www.devx.com/dbzone/Article/22119

Перевод Феськов Кузьма

 
 » Обсудить эту статью на форуме

 
 Сборник статей 
 Содержание раздела 
Есть еще вопросы или что-то непонятно - добро пожаловать на наш  форум портала PHP.SU 
 

 
Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS