Исключительная ситуация транзакция не активна. Проблема связанных SQLNCLI серверов. «Никакая транзакция не активна. Большое количество выполняемых операций

install create (4)

cursor = connection . cursor () cursor . executemany ("insert into person(firstname, lastname) values (?, ?)" , persons ) connection . commit ()

Я пытаюсь закодировать индексатор книг, используя Python (традиционный, 2.7) и SQLite (3).

Код сводится к этой последовательности операторов SQL:

"select count(*) from tag_dict" () /* [(30,)] */ "select count(*) from file_meta" () /* [(63613,)] */ "begin transaction" () "select id from archive where name=?" ("158326-158457.zip" ,) /* [(20,)] */ "select id from file where name=? and archive=?" ("158328.fb2" , 20 ) /* [(122707,)] */ "delete from file_meta where file=?" (122707 ,) "commit transaction" () # error: cannot commit - no transaction is active

Уровень изоляции «DEFERRED» («ЭКСКЛЮЗИВ» не лучше).

Я попытался использовать connection.commit () вместо cursor.execute ("commit") - ничего полезного не произошло.

  • Конечно, я искал и Net, но найденные ответы не имеют значения.
  • Режим автокомпозиции неприемлем по причине производительности.
  • Я использую только файл базы данных за раз.
  • Мой код работает в одном потоке.
  • Все выполнение SQL выполняется с помощью единственной функции, которая гарантирует, что я могу одновременно открыть не более одного курсора.

Итак, что случилось с транзакцией здесь?

Если я использую connection.commit () (обратите внимание: нет метода connection.begin!), Тогда я просто теряю свои данные.

Конечно, у меня есть doube / triple / quaruple проверенные разрешения файлов в файле базы данных и его каталоге.

Ну, как это часто бывает, я нашел решение через минуту после постановки вопроса.

Как новичок, я не могу ответить на свой вопрос в течение 8 часов... Итак, андер теперь есть:

Решение было и состоит из единственной идеи.

Я пытаюсь выполнить хранимую процедуру и просто вставлять ее результаты во временную таблицу, и я получаю следующее сообщение:

Операция не может быть выполнена, поскольку поставщик OLE DB «SQLNCLI» для связанного сервера «MyServerName» не смог начать распределенную транзакцию. Поставщик OLE DB «SQLNCLI» для связанного сервера «MyServerName» возвратил сообщение «Никакая транзакция не активна».

Мой запрос выглядит так:

INSERT INTO #TABLE EXEC MyServerName.MyDatabase.dbo.MyStoredProcedure Param1, Param2, Param3

Точный номер столбца, имена, проблема не является результатом.

MSDTC разрешен и запущен на обоих компьютерах, также вызывает удаленную процедуру.

Машины не находятся в одном домене, но я могу выполнять удаленные запросы с моей машины и получать результат. Я даже могу выполнить хранимую процедуру и увидеть ее результаты, я просто не могу вставить ее в другую таблицу.

Помоги пожалуйста? :)

<�Сильный> ИЗМЕНИТЬ

О, я забыл упомянуть, хранимая процедура не срабатывает. Он только вставляет записи во временные таблицы, которые он создает для обработки данных.

3

3 ответы

Ну, после того, как после нескольких уроков и много об этом поработал, я изменил всю конфигурацию, которая, как мне казалось, была необходима для ее работы, но это все равно не изменилось.

Сегодня нам пришлось принудительно перезагрузить компьютер на нашем сервере разработки из-за неисправности без разрыва, и когда мы загрузили сервер, угадайте, что? Оно работает!

Поэтому для записи я изменил определенную конфигурацию MSDTC, добавил ее как связанный сервер и разрешил RPC IN и OUT, а также изменил конфигурацию RPC для «НЕТ АУТЕНТИФИКАЦИИ ТРЕБУЕТСЯ» или что-то в этом роде.

Я помню, где-то читал, что после изменения этой конфигурации требуется перезагрузка, хотя Windows говорит, что она уже перезапустила службу.

Я перезагрузил свой сервер, как... дважды, так как я его изменил, и он все еще не работает. Но как сегодня, после полного отключения и включения, это работает!

Что касается синтаксиса, я сохранил то же самое.

Вы также должны проверить разрешение имен DNS в конфигурации IP-сети.

Например, у вас есть сервер под названием server-a.mydomain.com, а другой - server-b.otherdomain.com, войдите в сервер-a и выполните «ping-server-b» (без домена).

Если он отвечает: «Запрос Ping не смог найти хост-сервер-b. Пожалуйста, проверьте имя и повторите попытку». это проблема.

Go to the Control Pannel > Network Connections > Right click in the network card > properties > Internet Protocol > Properties > Advanced > DNS > Append this DNS suffix in order. And here add the local domain: mydomain.com and then add the remote domain: otherdomain.com Click OK until you exit

Теперь, если вы выполняете «ping-server-b», он должен отвечать на что-то вроде.

В рамках подготовки к сертификации 1С «Эксперт» в преддверии двух очень важных и глобальных тем — блокировок и хотелось бы разобрать то, без чего невозможны вышеназванные понятия, — транзакция СУБД.

Транзакция — логически связанная, неделимая последовательность действий. Транзакция может быть либо выполнена целиком, либо вообще не выполнена. Для фиксации транзакции в СУБД используется метод COMMIT.

Типичный пример транзакции — перевод денежных средств с одного счета на другой:

  1. начать транзакцию;
  2. прочесть количество денежных средств на счету номер 123;
  3. уменьшить баланс счета 123 на 100 рублей;
  4. сохранить баланс счёта номер 123;
  5. прочесть количество денежных средств на счету номер 321;
  6. увеличить баланс на 100 рублей;
  7. записать новое количество денежных средств на счете 321;
  8. зафиксировать транзакцию.

Получите 267 видеоуроков по 1С бесплатно:

Как мы видим, если транзакция выполнена не полностью, то она не имеет смысла.

Ключевые требования (ACID) к транзакционной СУБД

Одним из наиболее распространённых наборов требований к транзакциям и транзакционным СУБД является набор ACID (Atomicity, Consistency, Isolation, Durability). Это те свойства, которыми должна обладать любая транзакция:

  • Атомарность (Atomicity) — никакая транзакция не должна быть зафиксирована частично;
  • Согласованность (Consistency) — система находится в согласованном состоянии до начала транзакции и должна остаться в согласованном состоянии после завершения транзакции;
  • Изолированность (Isolation) — во время выполнения транзакции параллельные транзакции не должны оказывать влияние на её результат;
  • Надежность (Durability) — в случая сбоя изменения, сделанные успешно завершённой транзакцией, должны остаться сохранёнными после возвращения системы в работу.

Транзакции в 1С

Транзакции в 1С 8.3 и 8.2 создаются как автоматически, так и описываются разработчиками.

С помощью метода ТранзакцияАктивна() можно узнать, активна ли транзакция.

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

В прошлый раз мы рассмотрели простейший способ средствами встроенного языка 1С. На практике транзакции гораздо чаще используются совместно с конструкцией . Это позволяет в случае ошибки продолжить выполнение кода, а также выдать адекватное сообщение об ошибке пользователю и записать информацию в журнал регистрации или в файл логов для последующего анализа администратором системы.

Если мы обратимся к технической документации или к диску ИТС, то увидим, что фирма 1С рекомендует следующий способ организации транзакции в попытке

Попытка //1. Начало транзакции. НачатьТранзакцию() ; //2. Блок операций, выполняющихся в транзакции. //3. Если все операции успешны, фиксируем транзакцию. ЗафиксироватьТранзакцию() ; Исключение //4. Если при выполнении кода возникли ошибки, отменяем транзакцию. ОтменитьТранзакцию() ; //5. При необходимости запись в журнал регистрации. //6. При необходимости вывод сообщения пользователю. КонецПопытки ;

Собственно каких-то особых пояснений код не требует. Если в процессе попытки выполнения транзакционного кода возникает ошибка, мы сразу проваливаемся в блок исключение , т.е. до метода ЗафиксироватьТранзакцию() мы просто не доходим. Ну а в исключении соответственно отменяем транзакцию и если это необходимо выводим сообщение об ошибке и записываем информацию в журнал регистрации. Фиксировать ошибки в журнале регистрации крайне желательно, особенно для тех операций, которые выполняются без участия пользователя (например, регламентные задания). Это позволит в дальнейшем проанализировать ошибку. Вместо записи в журнал регистрации можно организовать отправку сообщений администратору по электронной почте.

Теперь вооружившись новыми знаниями попробуем видоизменить код, рассмотренный в статье про . Напомню, что мы рассматривали запись в справочник Товары и в регистр сведений Цена по следующей схеме:

&НаСервереБезКонтекста НачатьТранзакцию() ; //записываем новый товар Товар = Справочники. Товары. СоздатьЭлемент() ; Товар. Наименование = "Дырокол" ; Товар. Записать() ; //записываем цену НаборЗаписей = РегистрыСведений. Цена. СоздатьНаборЗаписей() ; НоваяЗапись = НаборЗаписей. Добавить() ; НоваяЗапись. Период = ТекущаяДата() ; НоваяЗапись. Товар = Товар. Ссылка; НоваяЗапись. Сумма = 100 ; НаборЗаписей. Записать() ; ЗафиксироватьТранзакцию() ; КонецПроцедуры

А теперь поместим транзакцию в блок Попытка Исключение . Скорее всего ошибки могут возникнуть только в момент записи в справочник или в регистр сведений, поэтому предварительную подготовку вынесем за пределы транзакции.

&НаСервереБезКонтекста Процедура ВыполнитьТранзакциюНаСервере() //создаем новый товар Товар = Справочники. Товары. СоздатьЭлемент() ; Товар. Наименование = "Дырокол" ; //Создаем запись с ценой НаборЗаписей = РегистрыСведений. Цена. СоздатьНаборЗаписей() ; НоваяЗапись = НаборЗаписей. Добавить() ; НоваяЗапись. Период = ТекущаяДата() ; НоваяЗапись. Сумма = 100 ; //Выполняем транзакцию в попытке Попытка НачатьТранзакцию() ; Товар. Записать() ; НоваяЗапись. Товар = Товар. Ссылка; НаборЗаписей. Записать() ; ЗафиксироватьТранзакцию() ; Исключение ОтменитьТранзакцию() ; Сообщение = Новый СообщениеПользователю; Сообщение. Текст = ; Сообщение. Сообщить() ; ЗаписьЖурналаРегистрации("Произошла ошибка при записи товара и его цены" ) ; КонецПопытки ; КонецПроцедуры

Как НЕ НАДО делать

У тех кто только начинает работать с транзакциями зачастую возникает желание сделать вот таким образом

НачатьТранзакцию() ; Попытка НачатьТранзакцию() ; //Блок операций ЗафиксироватьТранзакцию() ; Исключение ОтменитьТранзакцию() ; КонецПопытки ; Попытка НачатьТранзакцию() ; //Блок операций ЗафиксироватьТранзакцию() ; Исключение ОтменитьТранзакцию() ; КонецПопытки ; ЗафиксироватьТранзакцию() ;

Или в цикле

НачатьТранзакцию() ; Для каждого Данные Из МассивДанных Цикл Попытка НачатьТранзакцию() ; Данные. Записать() ; ЗафиксироватьТранзакцию() ; Исключение ОтменитьТранзакцию() ; КонецПопытки ; КонецЦикла ; ЗафиксироватьТранзакцию() ;

На первый взгляд мы сделали все в соответствии с рекомендациями фирмы 1С. Но дело в том, что платформа 1С не поддерживает вложенные транзакции. То есть чисто технически так писать можно. Но при этом все вложенные транзакции не образуют новые, а относятся к той же самой транзакции верхнего уровня. Таким образом, если в одной из вложенных транзакций произойдет ошибка, следующую вложенную транзакцию нельзя будет зафиксировать. Система выдаст сообщение вида: «В данной транзакции уже происходили ошибки!» . Продемонстрируем это на примере. Допустим мы решили записать два товара, каждый в своей транзакции. И сделаем эти транзакции вложенными в третью. Далее искусственно вызовем ошибку в первой транзакции с помощью метода ВызватьИсключение :

&НаСервереБезКонтекста Процедура ВыполнитьТранзакциюНаСервере() НачатьТранзакцию() ; Попытка НачатьТранзакцию() ; Товар = Справочники. Товары. СоздатьЭлемент() ; Товар. Наименование = "Стол" ; Товар. Записать() ; ВызватьИсключение "Ошибка записи товара." ; ЗафиксироватьТранзакцию() ; Исключение ОтменитьТранзакцию() ; Сообщение = Новый СообщениеПользователю; Сообщение. Текст = ОписаниеОшибки() Попытка НачатьТранзакцию() ; Товар = Справочники. Товары. СоздатьЭлемент() ; Товар. Наименование = "Стул" ; Товар. Записать() ; ЗафиксироватьТранзакцию() ; Исключение ОтменитьТранзакцию() ; Сообщение = Новый СообщениеПользователю; Сообщение. Текст = ОписаниеОшибки() ; Сообщение. Сообщить() ; КонецПопытки ; ЗафиксироватьТранзакцию() ; КонецПроцедуры

В результате выполнения этой процедуры увидим в окне сообщений следующее:

{ВнешняяОбработка.ТранзакцииВПопытке.Форма.Форма.Форма(20)}: Ошибка записи товара. {ВнешняяОбработка.ТранзакцииВПопытке.Форма.Форма.Форма(40)}: Ошибка при вызове метода контекста (Записать): В данной транзакции уже происходили ошибки!

Таким образом, организация вложенных транзакций в 1С абсолютно бессмысленна.

Возможные варианты

Теперь вернемся к варианту, где мы записывали товар и цену для него. Если у нас при выполнении транзакции произойдет ошибка, то будет трудно понять в какой момент она произошла — при записи товара или при записи цены, поскольку и то и другое происходит в рамках одной попытки. Чтобы определить место возникновения ошибки, нам надо каждую операцию записи заключить в свою собственную попытку и при этом избежать вложенных транзакций. Для этого введем булеву переменную Отказ и в зависимости от ее значения в конце всех операций будем фиксировать или отменять транзакцию.

&НаСервереБезКонтекста Процедура ВыполнитьТранзакциюНаСервере() // Начинаем транзакцию Отказ = Ложь ; НачатьТранзакцию() ; // Пытаемся записать товар Попытка Товар = Справочники. Товары. СоздатьЭлемент() ; Товар. Наименование = "Дырокол" ; Товар. Записать() ; Исключение Отказ = Истина ; Сообщение = Новый СообщениеПользователю; Сообщение. Текст = "Ошибка при записи товара" ; Сообщение. Сообщить() ; КонецПопытки ; // Пытаемся записать цену Попытка НаборЗаписей = РегистрыСведений. Цена. СоздатьНаборЗаписей() ; НоваяЗапись = НаборЗаписей. Добавить() ; НоваяЗапись. Период = ТекущаяДата() ; НоваяЗапись. Товар = Товар. Ссылка; НоваяЗапись. Сумма = 100 ; НаборЗаписей. Записать() ; Исключение Отказ = Истина ; Сообщение = Новый СообщениеПользователю; Сообщение. Текст = "Ошибка при записи цены" ; Сообщение. Сообщить() ; КонецПопытки ; // Фиксируем или отменяем транзакцию Если НЕ Отказ Тогда ЗафиксироватьТранзакцию() ; Иначе ОтменитьТранзакцию() ; КонецЕсли ; КонецПроцедуры

Аналогичным образом можно поступить и когда мы перебираем и записываем какие-либо данные в цикле. В этом случае мы сможем получить перечень всех данных с ошибками, если такие будут.

3

Я пытаюсь выполнить хранимую процедуру и просто вставить ее результаты во временную таблицу, и я получаю следующее сообщение:

Операция не может быть выполнена, поскольку поставщик OLE DB «SQLNCLI «для связанного сервера« MyServerName »не удалось начать распределенную транзакцию. Поставщик OLE DB «SQLNCLI» для связанного сервера «MyServerName» возвратил сообщение «Никакая транзакция не активна».

Мой запрос выглядит следующим образом:

INSERT INTO #TABLE EXEC MyServerName.MyDatabase.dbo.MyStoredProcedure Param1, Param2, Param3

Точное число колонки, имена, проблема не является результатом.

MSDTC разрешен и запущен на обоих компьютерах, удаленный вызов процедуры тоже.

Машины не в том же домене, но я могу выполнять удаленные запросы с моей машины и получать результат. Я даже могу выполнить хранимую процедуру и увидеть ее результаты, я просто не могу вставить ее в другую таблицу.

Помогите, пожалуйста? :)

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

  • 3 ответа
  • Сортировка:

    Активность

3

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

Сегодня нам пришлось принудительно перезагрузить компьютер на нашем сервере разработки из-за неисправности без разрыва, и когда мы загрузили сервер, угадайте, что? Оно работает!

Так что для записи я изменил определенную конфигурацию MSDTC, добавил ее как связанный сервер и разрешил RPC IN и OUT, а также изменил конфигурацию RPC для «НЕТ АУТЕНТИФИКАЦИИ ТРЕБУЕТСЯ» или что-то в этом роде.

Я помню, как где-то читал, что после того, как вы изменили эту конфигурацию, потребовалась перезагрузка, хотя Windows заявила, что она уже перезапустила службу.

Я перезагрузил свой сервер, как... дважды, так как я изменил его, и он все еще не работает. Но как сегодня, после полного отключения и включения, это работает!

Что касается синтаксиса, я сохранил то же самое.

2

Вы пробовали использовать openquery?

Insert into table select * from openquery(myservername, "exec mydatabase.dbo.mystoredproc param1, param2, param3")

0

Из MSDN документации: (http://msdn.microsoft.com/en-us/library/ms188427(SQL.90).aspx) В SQL Server 2000 и более поздних версий, OPENQUERY не могут быть использованы для выполнения расширенные хранимые процедуры на связанном сервере. Однако расширенная хранимая процедура может быть выполнена на связанном сервере с использованием имени из четырех частей. Например: EXEC SeattleSales.master.dbo.xp_msver - Smur 28 май. 10 2010-05-28 20:52:56

1

Вы также должны проверить разрешение DNS-имен в конфигурации IP-сети.

Например, у вас есть сервер под названием server-a.mydomain.com, а другой - server-b.otherdomain.com, войдите в сервер-a и выполните «ping-server-b» (без домена).

Если он отвечает «Запрос Ping не смог найти хост-сервер-b. Пожалуйста, проверьте имя и повторите попытку». это проблема.

Перейти к панели управления> Сетевые подключения> Щелкните правой кнопкой мыши на сетевой карте> Свойства> Интернет-протокол> Свойства> Дополнительно> DNS> Добавьте этот DNS-суффикс по порядку. И здесь добавить локальный домен: mydomain.com, а затем добавить удаленный домен: otherdomain.com Нажмите OK, пока не закроется

Теперь, если вы выполните «пинг сервера б» он должен repond что-то вроде.