Шаг 23 - Классы объектов, поддерживающие транзакции. Продолжение.
Шаг 23 - Классы объектов, поддерживающие транзакции. Продолжение.
Раз уж взялись, что мешает вставить в наш умный указатель с поддержкой отмены не один, а несколько предыдущих состояний объекта? Ничего. Только чтобы потом несколько раз не переделывать, решим несколько чисто технических моментов:
1. Какую структуру будем использовать в качестве коллекции состояний? Можно взять стек, можно кольцевой буфер, а можно и карту (словарь, хэш-таблицу); стек явно проще, зато за кольцевым буфером можно не следить вообще, пусть устаревшие состояния пропадают бесследно (конечно по желанию).
2. Определимся с семантикой. Смешивать значения и указатели не стоит, верный путь заработать себе геморрой. У меня не оказалось под рукой подходящего стека, и я написал для этого Шага два варианта - один хранит значения, другой - указатели; первый стек сначала казался проще, но использующий его класс указателя оказался ощутимо сложнее по простой причине - функции стека с указателями могут возвращать NULL, а это совсем немало.
3. Оформим все в виде шаблонов; вообще контейнеры просто просятся быть шаблонами, а smart-указатели несомненно являются контейнерами.
Код ниже, а сейчас пояснения:
Класс CType просто проверочный, чтобы вкладывать в шаблоны; так проще отлаживать шаблон: сначала сделать контейнер-не-шаблон для класса Type, а потом просто приписать сверху объявления строку template‹Type›. Шаблон класса ampstack‹Type› - шаблон стека указателей; push сохраняет указатель, pop достает верхний указатель, isEmpty проверяет на пустоту, emptyAll очищает.
Шаблон класса MLTrans - наконец тот, который нам нужен. Указатель that хранит текущее значение, Push сохраняет текущее значение, PopOne делает однократную отмену, Rollback отменяет все изменения, до первоначального, Commit удаляет историю.
// Это маленький класс для проверки
class CType {
int a;
public:
void set (int _a) { a=_a; }
int get (void) { return a; }
};
// Шаблон стека
template ‹class Type›
class ampstack {
private:
int iTop; // верх стека
int iSize; // размер стека
Type** array; // массив указателей
public:
// Конструктор-деструктор
ampstack(int size=10) : iTop(0), iSize(size), array(new Type*[size]) {}
~ampstack() {
for (int iCounter = 0; iCounter ‹ iTop; iCounter ++)
if (*(array+iCounter)!= NULL) delete *(array+iCounter);
delete[] array;
}
// Управление стеком
// Направить указатель в стек
void push (Type* _t) { array[iTop++]=_t; }
// Вынуть указатель из стека
Type* pop (void) {
if (iTop == 0) return NULL;
else return array[--iTop];
}
// Стек пуст?
int isEmpty (void) { return iTop==0; }
// Очистить стек
void emptyAll (void) {
for (int iCounter = 0; iCounter ‹ iTop; iCounter ++)
if (*(array+iCounter)!= NULL) delete *(array+iCounter);
iTop = 0;
}
};
// Шаблон класса с многоуровневой отменой
template ‹class Type›
class MLTrans {
typedef ampstack‹Type› stack;
private:
Type* that; // Текущее значение
stack history; // контейнер предыдущих значений
public:
// конструктор-деструктор
MLTrans(): that(new Type) {}
~MLTrans () { delete that; }
// Сохранение текущего значения, aналог SAVE TRANSACTION в SQL серверах
void Push() {
history.push(that);
that = new Type(*that);
}
// удаление промежуточных состояний
void Commit () { history.emptyAll(); }
// Откат на одну позицию; уничтожает текущее значение.
void PopOne() {
if (!history.isEmpty()) {
delete that;
that = history.pop();
}
}
// Откат к началу транзакции.
void Rollback() {
Type* old = history.pop();
Type* older = NULL;
if (old!= NULL) {
while ((older = history.pop())!= NULL) {
delete old;
old = older;
}
delete that;
that = old;
}
}
// Переопределенный operator-›
Type* operator-›() { return that; }
}
// проверим работу
int main() {
int t;
MLTrans‹CType› a;
a-›set(5);
t = a-›get();
a.Push();
a-›set(6);
t = a-›get();
a.Push();
t = a-›get();
a-›set(7);
t = a-›get();
a.Push();
t = a-›get();
a-›set(9);
t = a-›get();
// a.Push();
t = a-›get();
a.PopOne();
t = a-›get();
a.Rollback();
t = a-›get();
return 0;
}
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Автоматические транзакции
Автоматические транзакции Для разрешения провайдеру самостоятельно управлять транзакциями нужно указать в строке инициализации параметр "auto_commit=true":Call сn.Open("data source=localhost:d:databaseemployee.gdb;auto_commit=true","gamer", "vermut")В этом случае все создаваемые объекты сессий для данного источника
Распределенные транзакции
Распределенные транзакции Еще одним способом инициирования транзакции является подключение сессии к координатору распределенных транзакций. В общих чертах, координатор представляет собой сессию, транслирующую вызовы собственных интерфейсов управления транзакциией
Классы объектов и конкретные объекты
Классы объектов и конкретные объекты Есть одно формальное обстоятельство, которое следует запомнить. Существует различие между конкретными объектами и теми образцами, на основе которых данные объекты создаются. Конкретный объект представляет отдельный документ,
Шаг 22 - Классы объектов, поддерживающие транзакции.
Шаг 22 - Классы объектов, поддерживающие транзакции. Бывает особенно приятно, когда занимаешься теорией. Занимаешься, думаешь: "ну никакой связи с жизнью, хоть бы минимум пользы"… и вдруг раз! и польза является во всей своей красе, блистая в лучах солнца и хрустя пачками
Шаг 28 - Классы объектов, поддерживающие транзакции. Продолжение 2.
Шаг 28 - Классы объектов, поддерживающие транзакции. Продолжение 2. Классы объектов, хранящие состояния, получились очень неплохие - при минимальных интеллектуальных затратах, хотя о транзакциях говорить рано: для транзакций они недостаточно кислотные. (ACID - Atomic, Consistent,
Транзакции
Транзакции Все задачи пользователей в Firebird помещаются внутрь транзакций. Задача начинается с оператора START TRANSACTION и завершается, когда выполненная работа подтверждается (commit) или отменяется (rollback). Задача пользователя может выполнять множество запросов к операциям в
Транзакции и MGA
Транзакции и MGA MGA (Multi-Generational Architecture, многоверсионная архитектура) является названием основной архитектурной модели управления состоянием базы данных Firebird.В модели MGA каждая строка, сохраняемая в базе данных, содержит уникальный идентификатор той транзакции, которая ее
Транзакции в isql
Транзакции в isql Управление транзакциями в isql отличается в зависимости от того, вводите ли вы оператор DDL, команду SHOW или другие виды операторов.Когда isql стартует, она запускает транзакцию с уровнем изоляции SNAPSHOT (параллельный) с установкой разрешения блокировок WAIT. Если
Восстановление транзакции
Восстановление транзакции При использовании gfix, вы имеете множество режимов для получения информации и для разрешения зависших транзакций после ошибок двухфазного подтверждения. Процесс идентификации зависших транзакций и их подтверждение либо откат называется
Поддерживающие сэмплы
Поддерживающие сэмплы Поддерживающие сэмплы, как и сэмплерные петли, могут воспроизводиться в бесконечном цикле, но в этом случае повторяется не весь сэмпл, а только его часть. Определение такого повторяющегося фрагмента несколько усложняет создание поддерживающих
Лекция 13. Поддерживающие механизмы
Лекция 13. Поддерживающие механизмы Выше рассмотрены все основные методы создания ОО-программного продукта, кроме одного важнейшего набора механизмов. Недостающий раздел - наследование и все, что к нему относится. Перед тем как перейти к этой последней составляющей
Отложенные классы как частичные интерпретации: классы поведения
Отложенные классы как частичные интерпретации: классы поведения Не все отложенные классы так близки к АТД как STACK. В промежутке между полностью абстрактным классом, таким как STACK, в котором все существенные компоненты отложены, и эффективным классом, таким как FIXED_STACK,
У14.5 Классы без объектов
У14.5 Классы без объектов Не разрешается создавать объекты отложенных классов. В одной из предыдущих лекций был указан другой способ создания класса без объектов: включить в него пустую процедуру создания. Эквивалентны ли эти два механизма? Можно ли выделить случаи, когда