Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
Здравствуйте !
Есть проходная предприятия, где люди проходя прикладывают пропуск к сканеру. Сканер считывает код и запускает процедуру обработки.
Процедура делает следующее
1. Записывает поступивший код в базу (подключена локальная база на .MDB) - логирует
2. Формирует запрос на поиск сотрудника
3. Ищет сотрудника в базе. К ShowEmployee подключён TDataSource и TDBImage+TDBText. Фото и ФИО найденного сотрудника отображается на мониторе.
4. Если сотрудник найден, то он записывается в таблицу регистрации
5. И запускается процедура обработки списка регистрации таймером.
procedure DoEnterCode(Code: string);
var Id: integer;                                    
begin
  if Code = '' then Exit;
  ShowEmployee.Close;
  while Length(Code)>0 do // удаляем ведущие ноли
    if Code[1] = '0' then Delete(Code,1,1) else Break;
  ExecSQL('insert into ALog(ANumber,ADate) select :N,:D',[Code,Now()]);  // запись в таблицу логирования
  ShowEmployee.SQL.Text := 'select * from Employee E where TabNumber = '''+Code+'''';  // формируем запрос на поиск сотрудника
  ShowEmployee.Open; // здесь сотрудник найден и показывается на экране монитора 
  if not ShowEmployee.IsEmpty then // если запрос вернул сотрудника
    ExecSQL('insert into EmployeeRegistration(IdEmployee,ADate) values(:IdEmployee,:ADate)',[ShowEmployee['IdEmployee'],Now()]); // записываем сотрудника в базу
  ShowEmployeeRegistration.Execute; // обновляем список зарегистрированных сотрудников
  Timer1.Enabled := true; // запускаем таймер на обработку списка
end;


+ Обработка списка происходит следующим образом
1. Если есть в списке люди
2. Создаётся поток, который запускает хранимую процедуру на MSSQL и пытается записать сотрудника в базу
3. Если процедура вернула значение (возвращается ID сотрудника), то есть запись в базу произошла, то этот сотрудник из списка удаляется и таймер запускается снова.
procedure Timer1Timer(Sender: TObject);
var Id: integer;
    A: TADOThread;
    S: string;                           
begin
  Timer1.Enabled := false;
  if not EmployeeRegistrationShow.IsEmpty then begin  // если есть люди в списке                                                                        
    A := TADOThread.Create(nil,ConnectStr); // создаётся поток
    A.OnAfterExecute := DoAfterExecute;  // здесь мы удаляем сотрудника если сервер ответил положительно
    A.OnThreadError := DoThreadError; // здесь мы гасим ошибку сервера об отсутствии связи
    S := 'exec EmployeeRegistrationChange '+IntToStr(EmployeeRegistrationShow['IdEmployee'])+','+
                IdClient+','+                                                                                                                                                                                               
                ''''+ FormatDateTime('yyyymmdd hh:mm:ss',EmployeeRegistrationShow['ADate'])+'''';        
    A.ExecQuery(S);
  end;                                       
end;


Проблема в следующем.
Приблизительно раз-два в неделю, сотрудник(разный) не попадает в базу. Количество сотрудников в день ~4000.
При этом его нет ни в таблице ALog ни в таблице EmployeeRegistration. В ALog пишется все полученные коды, а в EmployeeRegistration только найденные сотрудники
Но на экране монитора он есть! Это подтверждает камера видеонаблюдения, на которой видно и сотрудника и его фото на мониторе.
Помогите пожалуйста с идеей, как объяснить такое поведение. Или с идеей как изменить систему записи
30 июл 20, 08:28    [22175508]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
delphinotes
Member

Откуда: Санкт-Петербург
Сообщений: 347
Petrashkevich,

Может быть ExecSQL не делает Commit/AutoCommit? В какой момент фиксируется транзакция, до отображения карточки сотрудника, или где-то позже?
Что значит "здесь мы удаляем сотрудника если сервер ответил положительно"?

Сообщение было отредактировано: 30 июл 20, 08:49
30 июл 20, 08:51    [22175514]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
> В какой момент фиксируется транзакция, до отображения карточки сотрудника, или где-то позже?
// сначала пишем в ALog
ExecSQL('insert into ALog(ANumber,ADate) select :N,:D',[Code,Now()]);
// затем ищем сотрудника и отображаем его на экране
ShowEmployee.SQL.Text := 'select * from Employee E where TabNumber = '''+Code+'''';
ShowEmployee.Open; // сюда прицеплен TDatasoure + TDBImage 
// если сотрудник найден, то пишем его в EmployeeRegistration
if not ShowEmployee.IsEmpty then 
  ExecSQL('insert into EmployeeRegistration(IdEmployee,ADate) values(:IdEmployee,:ADate)',[ShowEmployee['IdEmployee'],Now()]);


>Что значит "здесь мы удаляем сотрудника если сервер ответил положительно"?
Есть 2 таблички ALog и EmployeeRegistration.
В ALog пишется всё, а в EmployeeRegistration пишутся найденные сотрудники, которые отобразились на экране и которых нужно отослать на сервер.
То есть, в EmployeeRegistration формируется список, который нужно выгрузить на сервер.
1. В таймере, перечитывается табличка EmployeeRegistration (список выгрузки).
2. Если там есть данные, то запускается поток в котором идёт попытка вызвать хранимку на Сервере.
3. Если Хранимка ответила положительно (вернула значение ID сотрудника, которого мы пытаемся выгрузить) то этот сотрудник удаляется из выгружаемого списка и запускается таймер снова - пункт №1
4. Если Хранимка не ответила (сбой в сети), то ничего не происходит, сотрудник остаётся в списке и при следующем итерации таймера его снова будут пытаться отослать на сервер.
Так таймер и крутится, пока список не пустой.

Но это всё лирика, проблема в другом. Сотрудник отображается на экране но его данных нет в ALog. А с ALog ничего не удаляется. Эта таблица введена специально для отслеживания всех поступивших кодов.
30 июл 20, 09:21    [22175523]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Petrashkevich,

какая то не правильная у вас бизнес-модель. Таймер зачем то приплетен...
30 июл 20, 09:29    [22175526]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
>какая то не правильная у вас бизнес-модель.
Пожалуйста, подскажите как правильно

>Таймер зачем то приплетен...
Таймер для итерации списка. К данной проблеме он отношения не имеет
30 июл 20, 09:45    [22175530]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Petrashkevich
>какая то не правильная у вас бизнес-модель.
Пожалуйста, подскажите как правильно

>Таймер зачем то приплетен...
Таймер для итерации списка. К данной проблеме он отношения не имеет

MSSQL достаточно мощный инструмент, что бы делать все там.
SQL Server Agent -> Jobs (вместо таймера)
По факту: на сервер через ХП должен передаваться код и все остальное должен делать сервере.

p.s.
автор
S := 'exec EmployeeRegistrationChange '+IntToStr(EmployeeRegistrationShow['IdEmployee'])+','+
                IdClient+','+                                                                                                                                                                                               
                ''''+ FormatDateTime('yyyymmdd hh:mm:ss',EmployeeRegistrationShow['ADate'])+'''';      

даже не знаю, как без мата охарактеризовать это, без обид
30 июл 20, 09:59    [22175539]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
>По факту: на сервер через ХП должен передаваться код и все остальное должен делать сервере.
Так всё и происходит.

Проблема в другом.
1. Сотрудник пишется в таблицу Логирования (локальная таблица Access)
2. Сотрудник отображается на экране (это видно на камере наблюдения)
3. Сотрудник пишется в список отправки на сервер. (локальная таблица Access)

Ни в ПЕРВОЙ ни во ВТОРОЙ таблице сотрудника нет, а на экране сотрудник ЕСТЬ!!!
И происходит это 1-2 раза в неделю. То есть за 5 дней проходит 5*4000=20 тысяч сотрудников и 1-2 куда то исчезают

Сообщение было отредактировано: 30 июл 20, 10:18
30 июл 20, 10:18    [22175543]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Petrashkevich
>По факту: на сервер через ХП должен передаваться код и все остальное должен делать сервере.
Так всё и происходит.

Проблема в другом.
1. Сотрудник пишется в таблицу Логирования (локальная таблица Access)
2. Сотрудник отображается на экране (это видно на камере наблюдения)
3. Сотрудник пишется в список отправки на сервер. (локальная таблица Access)

Ни в ПЕРВОЙ ни во ВТОРОЙ таблице сотрудника нет, а на экране сотрудник ЕСТЬ!!!
И происходит это 1-2 раза в неделю. То есть за 50 дней проходит 5*4000=20 тысяч сотрудников и 1-2 куда то исчезают

1) Логирование должно происходить на сервере. На клиенте не должно быть
ExecSQL('insert into ALog(ANumber,ADate) select :N,:D',[Code,Now()]);
и т.п.
2) Наиболее вероятное поведение, описанное вами, является следствием подвисшей транзакции. Какая причина сбоя, возможно криво передаются данные.
30 июл 20, 10:24    [22175546]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
Gerasimenko

1) Логирование должно происходить на сервере. На клиенте не должно быть
ExecSQL('insert into ALog(ANumber,ADate) select :N,:D',[Code,Now()]);
и т.п.

Как логироване должно происходить на сервере, если сервер недоступен ? Вот оборвалась связь, повис роутер, свет выключили, сервер не стартанул. Где всё это время хранятся данные ? Система работает без наличия сервера в сети. Сервер появился (связь восстановили) все записанные данные сбросились на сервер.

Gerasimenko

2) Наиболее вероятное поведение, описанное вами, является следствием подвисшей транзакции. Какая причина сбоя, возможно криво передаются данные.

Данных нет ни в ПЕРВОЙ (локальной) таблице ни во ВТОРОЙ (локальной) ни на сервере.
Как ГАРАНТИРОВАННО записать в таблицу ACCESSа ?
Может быть перевести СПИСОК на отправку в Фаил ? То есть не писать это список в таблицу Access, а писать напрямую в текстовый файл ? Там блокировок не будет ?

Сообщение было отредактировано: 30 июл 20, 10:53
30 июл 20, 10:46    [22175555]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Petrashkevich
Gerasimenko

1) Логирование должно происходить на сервере. На клиенте не должно быть
ExecSQL('insert into ALog(ANumber,ADate) select :N,:D',[Code,Now()]);
и т.п.

Как логироване должно происходить на сервере, если сервер недоступен ? Вот оборвалась связь, повис роутер, свет выключили, сервер не стартанул. Где всё это время хранятся данные ?

Gerasimenko

2) Наиболее вероятное поведение, описанное вами, является следствием подвисшей транзакции. Какая причина сбоя, возможно криво передаются данные.

Данных нет ни в ПЕРВОЙ (локальной) таблице ни во ВТОРОЙ (локальной) ни на сервере.
Как ГАРАНТИРОВАННО записать в таблицу ACCESSа ?

1) вы противоречите себе сами.
автор
Как логироване должно происходить на сервере, если сервер недоступен ?

Тогда у что-то типа TStringList.SaveToFile.Да и в случае разрыва возникнет Exception
2)
автор
Создаётся поток, который запускает хранимую процедуру на MSSQL и пытается записать сотрудника в базу

зачем еще какой то ACCESS и уж тем более
автор
Создаётся поток

Вопросов больше чем ответов
30 июл 20, 10:55    [22175563]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Petrashkevich,
автор
Может быть перевести СПИСОК на отправку в Фаил ? То есть не писать это список в таблицу Access, а писать напрямую в текстовый файл ? Там блокировок не будет ?

Работайте напрямую с MSSQL.Что мешает там создать табличку со списком необработанных данных со сканера и запускать по расписанию Job
30 июл 20, 10:59    [22175564]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
> вы противоречите себе сами
Не виду противоречий

> Да и в случае разрыва возникнет Exception
Возникает, но гасится в событии OnThreadError, чтобы на экране не всплывало окно с ошибкой доступа. Сервер не ответил положительно, данные из таблички Регистрации не удаляются.

>зачем еще какой то ACCESS
Там хранится табличка сотрудников с их ФИО и ФОТО. Программа локальная, нужно где-то хранить данные сотрудников.

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

Смысл программы - накапливать данные и отсылать их на сервер когда тот появится в сети.
30 июл 20, 11:04    [22175567]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
>Работайте напрямую с MSSQL
Сервера нет в сети. Нет связи. Программа накапливает данные и отсылает их, когда связь восстанавливается
30 июл 20, 11:05    [22175568]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gluck99
Member

Откуда: Оттуда
Сообщений: 1038
Gerasimenko
2) Наиболее вероятное поведение, описанное вами, является следствием подвисшей транзакции. Какая причина сбоя, возможно криво передаются данные.
У него проблема не с MS SQL, а с Access. Вообще тут вместо тормознутого Access'a по идее достаточно простой записи в файл с разделителями. Потом для передачи на сервер формируем пакетом insert в одной транзакции. Если весь пакет ушёл нормально, то файл удаляем. Если транзакция откатилась, то файл с сотрудниками остаётся и продолжает пополняться.
С логами та же история - они пишутся локально в файл. Каждый день - новый файл. Логи можно периодически забрасывать на сервер, если надо их как-то сложно обрабатывать потом.
30 июл 20, 11:10    [22175572]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Petrashkevich
>Работайте напрямую с MSSQL
Сервера нет в сети. Нет связи. Программа накапливает данные и отсылает их, когда связь восстанавливается

1)С потоком все одно не понятно. MSSQL может общаться с ACCESS и наоборот.
2)хранить можно и в ACCESS и в текстовом файле. Причем во втором случае BULK INSERT очень удобен
3) Лучше на форуме по ACCESS спросить, почему откатывает. явного криминала нет
30 июл 20, 11:16    [22175575]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Gluck99
Gerasimenko
2) Наиболее вероятное поведение, описанное вами, является следствием подвисшей транзакции. Какая причина сбоя, возможно криво передаются данные.
У него проблема не с MS SQL, а с Access. Вообще тут вместо тормознутого Access'a по идее достаточно простой записи в файл с разделителями. Потом для передачи на сервер формируем пакетом insert в одной транзакции. Если весь пакет ушёл нормально, то файл удаляем. Если транзакция откатилась, то файл с сотрудниками остаётся и продолжает пополняться.
С логами та же история - они пишутся локально в файл. Каждый день - новый файл. Логи можно периодически забрасывать на сервер, если надо их как-то сложно обрабатывать потом.
Да... теперь понятно
30 июл 20, 11:17    [22175576]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gluck99
Member

Откуда: Оттуда
Сообщений: 1038
Petrashkevich
Сервера нет в сети. Нет связи. Программа накапливает данные и отсылает их, когда связь восстанавливается
У вас скорее всего проблема с таймером и подключением к Access. Я бы начал с проверки этой гипотезы.
30 июл 20, 11:22    [22175581]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4612
Gluck99
Petrashkevich
Сервера нет в сети. Нет связи. Программа накапливает данные и отсылает их, когда связь восстанавливается
У вас скорее всего проблема с таймером и подключением к Access. Я бы начал с проверки этой гипотезы.

1)я бы отбросил гипотезы и писал в текстовый файл
2) по доступности сервера : перекладывал файл на сервер.
3) на сервере пускай работает JOB по расписанию.
30 июл 20, 11:25    [22175582]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gluck99
Member

Откуда: Оттуда
Сообщений: 1038
Gerasimenko
2) по доступности сервера : перекладывал файл на сервер.
Это вообще лучше всего.
30 июл 20, 11:27    [22175583]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Кроик Семён
Member

Откуда: СПб --> Dortmund
Сообщений: 6629
Petrashkevich,


мысль 1

У меня такое чувство, что у вас время от времени происходит Exception где то между отображением на экране и логированием. Вот до логирования и не доходит, обрываясь раньше.

мысль 2

Так же возможно, что логирование у вас в if <...> then <логирование> и вы упустили какой-то из вариантов.

Сообщение было отредактировано: 30 июл 20, 11:37
30 июл 20, 11:37    [22175588]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
>С потоком все одно не понятно.
Потоком отсылается одна запись из списка накопленных. Почему потоком, чтобы не подвисала основная программа

>хранить можно и в ACCESS и в текстовом файле. Причем во втором случае BULK INSERT очень удобен
Советуете переделать хранение списка в текст ?

>Лучше на форуме по ACCESS спросить, почему откатывает. явного криминала нет
Как в Delphi отследить что запись всё таки вставлена и как её ГАРАНТИРОВАННО записать ?

>У вас скорее всего проблема с таймером и подключением к Access. Я бы начал с проверки этой гипотезы.
Как это можно проверить ?

>У меня такое чувство, что у вас время от времени происходит Exception где то между отображением на экране и логированием. Вот до логирования и не доходит, обрываясь раньше.
Сначала Логирование(запись в одну таблицу), потом Отображение (чтение из той же базы с другой таблицы), потом вторая запись в другую таблицу. Итого три операции с базой над тремя таблицами. Первая и Третья операции мимо, а средняя работает.

>Так же возможно, что логирование у вас в if <...> then <логирование> и вы упустили какой-то из вариантов.
У меня первое логирование без всяких условий (запись в ALog). Вторая запись уже по условию, если человек найден
30 июл 20, 12:13    [22175619]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Gluck99
Member

Откуда: Оттуда
Сообщений: 1038
Petrashkevich
Как это можно проверить ?
Надо чаще использовать try/except/finally. Вам нужно обернуть код вставки записей в БД аксеса в блоки обработки ошибок. Тогда по ошибке либо показывать сообщение, либо писать лог в текстовый файл с сообщением об ошибке и ID сотрудника, на котором произошел сбой. Кстати, это позволит вообще отказаться от таймера.
 try
    ExecSQL('insert into ALog(ANumber,ADate) select :N,:D',[Code,Now()]);  // запись в таблицу логирования
 except
      { Тут обрабатываем возможную ошибку }
 end;

    ShowEmployee.SQL.Text := 'select * from Employee E where TabNumber = '''+Code+'''';  // формируем запрос на поиск сотрудника
    ShowEmployee.Open; // здесь сотрудник найден и показывается на экране монитора

try 
    if not ShowEmployee.IsEmpty then // если запрос вернул сотрудника
      ExecSQL('insert into EmployeeRegistration(IdEmployee,ADate) values(:IdEmployee,:ADate)',[ShowEmployee['IdEmployee'],Now()]); // записываем сотрудника в базу
except
    { Тут обрабатываем возможную ошибку }
end;
Как использовать эти операторы посмотрите в справке - там всё исчерпывающе написано.

Сообщение было отредактировано: 30 июл 20, 13:23
30 июл 20, 13:25    [22175674]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
Petrashkevich
Member

Откуда:
Сообщений: 81
>Gluck99
Спасибо за идею обернуть в try/except и логировать в файл ошибку.
Попробую.
Конечно сомневаюсь, поскольку ExecSQL не глотает ошибки и они вываливались бы на экран. Но попытка- не пытка.
30 июл 20, 14:01    [22175697]     Ответить | Цитировать Сообщить модератору
 Re: Проблема с простеньким кодом  [new]
AltHasp
Member

Откуда:
Сообщений: 165
Petrashkevich,

Как вариант использовать FB Embedded - мы используем ее в связке с Fib+, еще после вставки записи - можно проверить на успешное выполнение команды вставки. Вообще ЖарПтица практически неубиваемая вещь! ИМХО.
31 июл 20, 10:25    [22175973]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить