Взаимодействие между объектами, работающими с БД: транзакции

Casey

Новичок
Взаимодействие между объектами, работающими с БД: транзакции

Доброго времени суток!

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

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

Но логика работы с самими данными, где одно из полей хранится в регистре также требует отдельнй транзакции на каждую логическую операцию!

Однако общий класс может использоваться и без "внешней" транзации, в простых случаях

Так и просятся вложенные транзакции, однако их в mysql нет, максимум что нашёл - savepoint, но функция не очень применима, т.к. класс не знает - открыта ли транзакция или нет.

Вопрос - как обходятся такие ситуации в крупных проектор, когда между собой взаимодействуют несколько объектов, каждый из которых работает со своими данными БД?
 

FractalizeR

Новичок
Правильно ли я понимаю, что вам не нужно иметь возможность частичного отката/фиксации изменений внутри самой внешней транзакции? Ведь если в процессе сохранения данных произошла ошибка при записи в ваш регистр, вся операция должна быть отменена, а не только запись в регистр, так?

Если такая возможность вам не нужна, то тогда зачем вложенные транзакции?

Мне кажется, удобным вариантом будет внесение изменений в ваш класс работы с базой данных таким образом, чтобы

PHP:
function startTransaction() {
  if(!this->transactionStarted()) {
  $result = mysql_query("START TRANSACTION", $this->_connection);
  if ($result===false) {
    throw new DBException($this, 'Error!');
  }
  }
}
Конечно, возникнет некоторая проблема, что внешний вызывающий класс не поймет, была ли транзакция подтверждена или откатана, если transactionStarted() = false. Но для этого можно ввести еще одну переменную transactionRolledBack() в объект соединения с базой данных, состояние которой можно проверять после того, как вы передали объект соединения с базой данных методу другого объекта.

PHP:
$db->startTransaction();
$userObject->performRegisterUpdate($db);
if($db->transactionRolledBack()) {
throw new Exception('Error occured');
}
Сорри за примитивный пример, но думаю, суть понятна.

Так и просятся вложенные транзакции, однако их в mysql нет, максимум что нашёл - savepoint, но функция не очень применима, т.к. класс не знает - открыта ли транзакция или нет.
Почему класс этого не знает? Разве в вашем проекте работа с базой данных не осуществляется через singleton-объект? Операторы MySQL по работе с транзакциями в проекте теоретически должны быть заменены вызовами методов объекта соединения с базой данных.
 
Сверху