Почему qry.post выполняется в асинхронном режиме? - PullRequest
2 голосов
/ 12 июня 2010

Недавно я столкнулся со странной проблемой, см. Фрагменты кода, как показано ниже:

var
  sqlCommand: string;
  connection: TADOConnection;
  qry: TADOQuery;
begin
  connection := TADOConnection.Create(nil);
  try
    connection.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.MDB;Persist Security Info=False';
    connection.Open();
    qry := TADOQuery.Create(nil);
    try
      qry.Connection := connection;
      qry.SQL.Text := 'Select * from aaa';
      qry.Open;

      qry.Append;
      qry.FieldByName('TestField1').AsString := 'test';

      qry.Post;
      beep;
    finally
      qry.Free;
    end;
  finally
    connection.Free;
  end;
end;

Во-первых, создайте новую базу данных доступа с именем test.mdb и поместите ее в каталог этого тестового проекта, мы можем создать новую таблицу с именем aaa, в которой будет только одно поле текстового типа с именем TestField1.

Мы устанавливаем точку останова в строке «beep», затем запускаем тестовое приложение в режиме отладки ide, когда ide останавливается в строке точки останова (qry.post был выполнен), в настоящее время мы используем доступ Microsoft для открытия теста .mdb и откройте таблицу aaa, вы увидите, что в таблице aaa нет никаких изменений, если вы позволите ide продолжить работу после нажатия клавиши f9, вы можете обнаружить, что новая запись вставлена ​​в таблицу aaa, но если вы нажмете Ctrl + F2, чтобы завершить В приложении в точке останова вы обнаружите, что в таблицу aaa не было вставлено ни одной записи, но в нормальных условиях новая запись должна быть вставлена ​​в таблицу aaa после выполнения qry.post. кто может объяснить эту проблему, так долго меня беспокоит. спасибо !!!

Кстати, идеей является delphi 2010, а файл mdb для доступа создается Microsoft Access 2007 под Windows 7

.

Ответы [ 3 ]

1 голос
/ 12 июня 2010

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


После получения дополнительной информации от Райана (см. Его ответ самому себе) я немного больше расследовал.

Наличие первичного ключа (автономного номера или другого), по-видимому, не влияет на поведение.

Таблица со столбцом автономного номера в качестве первичного ключа

  connection.Execute('insert into aaa (TestField1) values (''Test'')');
  connection.Execute('select * from aaa');
  connection.Execute('delete * from aaa');
  beep;
finally
  connection.Free;
end;

Остановка на «select» не показывает новую запись. Остановка на «Удалить» показывает новую запись. Остановка на "звуковой сигнал" по-прежнему показывает все записи в таблице, даже после повторных обновлений. Остановка на "connection.Free" не показывает больше записей в таблице. А? Остановка на «select», вставленном между «delete» и «beep», не показывает больше записей в таблице.

Та же таблица

  connection.Execute('insert into aaa (TestField1) values (''Test'')');
  beep;
  connection.Execute('delete * from aaa');
  beep;
  beep;

Остановка каждого оператора показывает, что Access не получает «команду», пока не будет выполнен хотя бы один другой оператор. Другими словами: сигнал после оператора «Execute» должен быть обработан до того, как оператор будет обработан Access (может потребоваться несколько обновлений для отображения, первое обновление не всегда достаточно). Если вы остановитесь на первом звуковом сигнале после оператора «Выполнить», в Access ничего не произойдет и не произойдет, если вы перезагрузите программу, не выполнив никаких других операторов.

Вступление в соединение. Execute (Использовать debug dcu's on): эффект от выполнения оператора sql теперь виден в Access при возврате в звуковой сигнал. На самом деле, это видно гораздо раньше. Например, входя в оператор «delete», запись становится помеченной #deleted где-то еще в коде ADODB.

Фактически, при пошаговом выполнении кода adodb запись становится видимой в Access при остановке в обработчике OnExecuteComplete. Не тогда, когда остановлено на «начало», а когда остановлено на «если назначено» сразу после этого. То же самое относится и к оператору удаления. Эффект становится видимым в Access при остановке в операторе if в обработчике OnExecuteComplete в AdoDb.

Ado имеет ExecuteOption для асинхронного выполнения операторов. Во время всего этого он не действовал (по умолчанию он не включен). И хотя мы имеем дело с внепроцессным COM-сервером и с обратными вызовами, такими как обработчик OnExecuteComplete, этот обработчик был выполнен перед возвратом к оператору сразу после оператора ConnectionObject.Execute в методе TAdoConnection.Execute в AdoDb.

В целом, я думаю, что это не столько вопрос синхронного или асинхронного выполнения, сколько вопрос о выпуске ссылок (мы имеем дело с COM и подсчетом ссылок на интерфейсы) или с проблемами синхронизации потоков и процессов (в приложении, Доступ и между ними) или с их комбинацией.

И отладчик может просто запутывать вещи, а не разъяснять их. Было бы интересно посмотреть, что происходит в D2010 с его возможностями отладки в одном потоке, но я не получил его там, где я нахожусь (сейчас и в течение следующих двух недель).

0 голосов
/ 18 июня 2010

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

Я, к счастью, решил проблему в соответствии со статьей. На самом деле значение по умолчанию свойства "Jet OLEDB: Implicit Commit Sync" равно false. Согласно объяснению этого свойства значение Be false подразумевает, что неявная транзакция будетиспользовать асинхронный режим.поэтому мы можем установить для этого свойства значение true, используя фрагменты кода, как показано ниже:

connection.Properties.Item['Jet OLEDB:Implicit Commit Sync'].Value := true;

Кстати, согласно этой статье, это свойство можно установить только с помощью свойства Properties объекта подключения,в противном случае, если он установлен в строке подключения, произойдет ошибка

0 голосов
/ 15 июня 2010

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

procedure TForm9.btn1Click(Sender: TObject);
var
  sqlCommand: string;
  connection: TADOConnection;
begin
  connection := TADOConnection.Create(nil);
  try
    connection.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.MDB;Persist Security Info=False';
    connection.Open();
    connection.Execute('insert into aaa (TestField1) values (''Test'')');
    connection.Execute('select * from aaa');
    connection.Execute('delete * from aaa'); // breakpoint 1
    beep;  // breakpoint2
  finally
    connection.Free;
  end;
end;

Поместите две точки останова в строки «delete» и «beep», когда коды остановились на точке останова 1, вы можете обновить базу данных, и вы обнаружите, что запись была вставлена, продолжить работу, когда коды остановились на точке останова 2, вы могли бы найти запись все еще там ..... Если в это время вы нажали ctrl + f2, запись не будет удалена .... если connection.execute - настоящая процедура sychronouse, это не должно происходить. извините за проверку вашего ответа так поздно, потому что я на нашем фестивале лодок-драконов ...

...