Название: Вложенные транзакции Отправлено: lolobotik от Ноябрь 16, 2017, 15:15 Здравствуйте.
Ситуация следующая. Есть SQL Server 2008, в программе используется драйвер QODBC3. Соединение установлено, данные пишутся/читаются. Проблема, видимо, в отсутствии понимания принципа работы с вложенными транзакциями. Судя по документации к восьмому серверу, каждый новый BEGIN TRANSACTION увеличивает счётчик TRANCOUNT на единицу. Каждый COMMIT уменьшает его на 1. Транзакция завершается и фиксируются изменения, когда счётчик станет равен 0. У меня же выходит, что первый же commit завершает транзакцию вне зависимости от того, сколько было BEGIN TRANSACTION. Пусть имеется база и запрос к ней: Код: db = QSqlDatabase::addDatabase("QODBC3"); Код: db.transaction(); В чём здесь проблема? Я совсем не правильно понял идею со счётчиком открытых транзакций, или просто драйвер/Qt не поддерживают такой функционал? Или я упустил что-то где-то в настройках (сервера/драйвера)? И на случай, если я совсем что-то не то творю и не тем образом, и есть более человеческий способ. Зачем мне вообще это нужно: Есть необходимость использовать внутри "составной" функции, состоящий из нескольких операций, функции "поменьше "(отдельно на каждую из операций). Функции "поменьше" могут вызываться и самостоятельно, поэтому обрамлены своим набором:db.transaction(),db.rollback(),db.commit(). В "составной" же всё действо обрамлено ещё одним набором открытия/закрытия транзакции ради того, что бы можно было разом откатить все входящие в её состав операции "поменьше", если где-то по ходу дела станет ясно, что всё пошло не так. Но задумка/реализация явно не удалась. Название: Re: Вложенные транзакции Отправлено: lolobotik от Ноябрь 16, 2017, 17:09 Сделаю пример чуть более страшным:
Код: bool ok; В результате имеем: Код: Transaction Count 1: 0 Выглядит так, будто первый вызов transaction() не инкрементирует счётчик транзакций в базе. Соответсвенно rollback() вызывается будто бы без открытой транзакции, так как первый commit() её и закрыл. Вопрос знатокам: Почему первое открытие транзакции может "игнорироваться"? Название: Re: Вложенные транзакции Отправлено: lolobotik от Ноябрь 16, 2017, 21:04 Покопался ещё немного: понял, что неверно истолковал полученные результаты. После первого INSERT'а из внешней транзакции счётчик всё-таки увеличивается (принимает значение = 1). Вот только после второго вызова transaction(), как и после INSERT'а внутри него, счётчик всё ещё показывает 1. Соответственно первый же COMMIT закрывает транзакцию полностью и откатывать уже нечего. Дабы не засорять тему дальше примерами кода и выводом полученного результата, просто опишу, какое значение счётчика считывается из базы после каждой операции.
db.transaction(); //@@TRANCOUNT = 0 query->exec("INSERT INTO TestOnly (Value) VALUES('1')"); //@@TRANCOUNT = 1 db.transaction(); //@@TRANCOUNT = 1 query->exec("INSERT INTO TestOnly (Value) VALUES('2')"); //@@TRANCOUNT = 1 db.commit(); //@@TRANCOUNT = 0 query->exec("INSERT INTO TestOnly (Value) VALUES('3')"); //@@TRANCOUNT = 0 db.rollback(); //@@TRANCOUNT = 0 Буду благодарен за любую подсказку по поводу того, почему счётчик не идёт дальше единицы. Название: Re: Вложенные транзакции Отправлено: lolobotik от Ноябрь 20, 2017, 10:28 Раз уж я тут столько настрочил, отвечу хотя бы сам на свои вопросы. По идее тему можно закрывать (или у вас так не принято после ответа на вопрос? :))
Помогли на русском stack overflow. Судя по всему, надо было мне исходниками по голове настучать, может быстрее разобрался бы. На самом деле transaction() не отправляет никаких команд о начале новой транзакции базе, он просто отключает автокоммит (справедливо, по крайней мере, для QODBC), соответственно каждая следующая операция не подтверждается до ручного COMMIT'а. А так как begin transaction никуда не отправляется, начать вложенную транзакцию описанным мною образом невозможно. "Begins a transaction on the database if the driver supports transactions." в описании функции ввело меня в заблуждение. Сейчас буду менять в коде все transaction()/commit()/rollback() на query->exec("begin tran"/"commit"/"rollback"). При такой работе с транзакциями всё отрабатывает так, как я хотел. |