Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 12.11.05 14:57
Оценка:
Возник такой вопрос. В БД (Access 2000) заносятся записи со скоростью приблизительно 8 записей в секунду (+- 3 записи). Записи успешно добавляются, вот код для их добавления
char *szQueryY="INSERT INTO `Y_Table` (`Num`,`WorkTime`,`Y`) VALUES (?,?,?);";
char *szQueryI="INSERT INTO `I_Table` (`Num`,`WorkTime`,`I`) VALUES (?,?,?);";
char *szQuery;

           switch(table)
           {
           case 'Y':szQuery=szQueryY; break;
           case 'I':szQuery=szQueryI; break;
           default: return false;                
           }
    
SQLPrepare(hstmt, (UCHAR*)szQuery, SQL_NTS); 


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_INTEGER, 
    SQL_INTEGER, 1, 0, &Num, 0, 0); 

SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_DOUBLE,   
    SQL_C_DOUBLE, 1, 0, &Time, 0, 0); 

SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_DOUBLE, 
    SQL_C_DOUBLE, 1, 0, &mean, 0, 0);

if(SQLExecute(hstmt)==SQL_ERROR)
{
     return false;
}

return true ;

}


Как я сказал, записи добавляются успешно. Но я немного лукавлю. Есть проблема, время от времени SQLExecute() возвращает SQL_ERROR. При этом входные данные подаются корректные (т.е. практически ничем не отличаются от тех, на которых SQL_Execute нормально отрабатывала). Никакой закономерности по времени и по входным данным не обнаружено. Т.е. я не могу сказать, что каждые 2 минуты происходит ошибка или при каких-то определенных значениях. Но я могу сказать, что чем дольше работает прога, тем ошибки появляются чаще. У меня складывается ощущеие, что это зависит от размера БД. Чем больше в ней записей, тем чаще ошибки. Если БД почистить, то некоторое время ошибки не выскакивают, но потом постепенно появляются, при этом как я говорил частота их появления возрастает.
Если БД не обнулять, но закрыть приложение, а потом опять запустить, то ошибки начинают выскакивать практически сразу (что косвенно подтверждает зависимость их появления от размеров БД)
У меня 2 вопроса:
1) Почему это происходит? Кто(что) в этом виноват?
2) Как с этим бороться? (Что делать? -Чернышевский).
Я пробовал подставить такой запрос
INSERT INTO `Y_Table` (`Num`,`WorkTime`,`Y`) VALUES (1,1,1);";
INSERT INTO `I_Table` (`Num`,`WorkTime`,`I`) VALUES (2,2,2);

Но ошибки все равно, время от времени выскакивали, что еще раз подтверждает, что дело не во входных даны.
Пробовал транзакции – добавлял в конце функции
SQLTransact(henv,hdbc,SQL_COMMIT);
Не помогло. Кстати эта функция нужна там или нет?
У меня есть на примете одно решение:
В случае, если запрос не удался делать Sleep() на 10-50мс и повторить запрос. Так до тех пор, пока запрос не проскочит, но не более 5 раз (к примеру, а то может и 2 или 10).
Но хотелось бы более элегантно решить эту проблему. К тому же попытка повторить запрос не гарантирует успех, т.к. уже пробовал повторять запрос второй раз в случае неудачи и бывало, что и второй раз подряд выскакивала ошибка.


Итак, работа происходит с БД – Microsoft Access 2000, используется ODBC (ну, я думаю, все догадались).

На всякий случай опишу структуру БД (а именно 2 таблицы, т.к. только в них трабблы):
№ Имя Тип
I_Table
1) Num счетчик (автоинкремент) Длинное целое
2) WorkTime Длинное целое
3) I Действительное

Y_Table
1) Num счетчик (автоинкремент) Длинное целое
2) WorkTime Действительное
3)Y Двойное с плавающей точкой

Структура БД не обсуждается .
Заранее спасибо за развернутые ответы.

P.s. Забыл написать как подключаюсь, мало ли пригодится
Codbc::Codbc()
{
                        //////////////
                        szUser[256] = 0;
                        szPass[256] = 0;
                        strcpy(szDsn,"mysource");
                        hstmt=NULL;
                        henv = NULL;
                        hdbc = NULL;
                        ///////////// 


if (::SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR)
{
   
   
    MessageBox(0,"error connect","error connect",0);
}

                 ::SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, 
                                (void*) SQL_OV_ODBC3, SQL_IS_INTEGER);

                                                     
                                     if ( ::SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR)
                                     {
                                       
                                      
                                       MessageBox(0,"error connect2","error connect2",0);
                                     }



if ( ::SQLConnect(hdbc, (SQLTCHAR*)szDsn, SQL_NTS,
        (SQLTCHAR*)szUser, _tcslen(szUser), (SQLTCHAR*)szPass, 
         _tcslen(szPass) ) == SQL_ERROR )
{
       
       
    MessageBox(0,"error connect source","error connect source",0);
}

                         if (::SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR)
            {
                 MessageBox(0,"Error zapros","Error zapros",0); 
                 
                
            }


}
Re: Win API & ODBC (отказ в создании записи )
От: wildwind Россия  
Дата: 12.11.05 15:37
Оценка:
Здравствуйте, NdF, Вы писали:

NdF>P.s. Забыл написать как подключаюсь, мало ли пригодится


Ты еще забыл написать, какую ошибку получаешь. Что в общем-то главное.
Re[2]: Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 12.11.05 15:39
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Здравствуйте, NdF, Вы писали:


NdF>>P.s. Забыл написать как подключаюсь, мало ли пригодится


W>Ты еще забыл написать, какую ошибку получаешь. Что в общем-то главное.


Пока никакую. Еще не применил SQLERROR(). Исправлю эту оплошность.
Re[3]: Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 12.11.05 16:13
Оценка:
W>>Ты еще забыл написать, какую ошибку получаешь. Что в общем-то главное.

szErrorMsg=Обновление невозможно; установлена блокировка
szSqlState=HY000
pcbErrorMsg=0.00000
У меня есть мыслишки, но мне стыдно их даже выражать, по сколько я с этим делом не сталкивался. Хотелось бы услышать (прочитать) мнение знающих людей.
Re[4]: Win API & ODBC (отказ в создании записи )
От: wildwind Россия  
Дата: 12.11.05 17:28
Оценка:
Здравствуйте, NdF, Вы писали:

NdF>szErrorMsg=Обновление невозможно; установлена блокировка

NdF>szSqlState=HY000
NdF>pcbErrorMsg=0.00000
Ну это мало о чем говорит. К тому же SQLERROR() уже давно deprecated, лучше используй SQLGetDiagRec(). Нужно получить ошибку в стандартном формате
[vendor-identifier][ODBC-component-identifier][data-source-identifier]data-source-supplied-text


NdF>У меня есть мыслишки, но мне стыдно их даже выражать, по сколько я с этим делом не сталкивался. Хотелось бы услышать (прочитать) мнение знающих людей.

Отчего же стыдно, наоборот давай выражай. Вместе же решаем проблему.

Я вот спрошу пока:
1) С базой работает только одно твое приложение, или данный код выполняет несколько пользователей 8 раз в секунду?
2) Счетчик Num в таблицах генерирует последовательные значеения или случайные?
Re[5]: Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 13.11.05 11:43
Оценка:
W>Ну это мало о чем говорит. К тому же SQLERROR() уже давно deprecated, лучше используй SQLGetDiagRec(). Нужно получить ошибку в стандартном формате
[vendor-identifier][ODBC-component-identifier][data-source-identifier]data-source-supplied-text
W>

Попробую.


W>Я вот спрошу пока:

W>1) С базой работает только одно твое приложение, или данный код выполняет несколько пользователей 8 раз в секунду?
W>2) Счетчик Num в таблицах генерирует последовательные значеения или случайные?

1)С базой работает 8 потоков одного приложения.
И у меня такая мысль, а не может такого быть, что один поток пытается занести свой запрос, в то время как заносится запрос другого потока. Может надо как-то разделить критический ресурс? А с другой стороны, что-то мне кажется, что БД сама как-то решает такие задачи (я по БД мало что знаю, точнее про механизмы работы СУБД).

2)Я перепутал, Num — Длинное целое. Это не primary key и не foreign key. Пока в таблице (в БД) нет никаких ограничений целостности.
Значение Num берется из другой таблицы. Попытаюсь сейчас поподробнее. Для каждого потока одно значение Num и оно для этого потока постоянно, т.е. если в приложении запущено 8 потоков, то в БД на данный момент в поле Num заносится 8 разных значение, которое постоянны.
Пример:
1)255 256 258 257 259 260 254 261
2
)261 256 257 258 259 255 260 254
Т.е. значения могут оказаться и перетасованы (порядок их в БД, хотя это не имеет смысла для БД ) но они постоянны.
Если один поток отрубить, а потом запустить, то по данному примеру этот поток будет в поле Num заносить значение 262.
Ну, как смог пояснил.
У меня такой вопрос возник, а не может дело быть в следующем:
Я в первом посте показал конструктор класса, так там послдение строки
if ( ::SQLConnect(hdbc, (SQLTCHAR*)szDsn, SQL_NTS,
        (SQLTCHAR*)szUser, _tcslen(szUser), (SQLTCHAR*)szPass, 
         _tcslen(szPass) ) == SQL_ERROR )
{
       
       
    MessageBox(0,"error connect source","error connect source",0);
}

             // Get a statement handle 
            if (::SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR)
            {
                 MessageBox(0,"Error zapros","Error zapros",0); 
                 
                
            }


Когда же я делаю запрос, я не делаю этих подключений и ничего не освобождаю. Все освобождаентся только в деструкторе.
Может надо функции SQLConnect и SQLAllocHandle вызывать перед каждым запросом и соответственно освободжать их после каждого запроса?
зы. Извеняюсь, что долго не отвечал, я думал у вас на форуме уведомления на почту приходят об ответе, оказалось что нужно галочку после каждогопоста ставить.
Re[6]: Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 13.11.05 13:17
Оценка:
Провел сейчас очередное "исследование". Был на длительное время запущен только один поток. он сделал в БД около 7 тысяч записей (больше я ждать не стал) и за это время не появилось ни одной ошибки. При 8 потоках ошибки уже начинают выскакивать примерно на 2 тысячах записей (может чуть позже).
Re[7]: Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 13.11.05 14:03
Оценка:
Вот так я вызывал функцию SQLGetDiagRec
SQLSMALLINT i = 1;
   while ((SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError,
            ErrorMsg, sizeof(ErrorMsg), &iErrorMsg)) != SQL_NO_DATA) {
     // DisplayError(SqlState,NativeError,Msg,&iErrorMsg);
      
       sprintf(s,"ErrorMsg=%s --- SqlState=%s --- iErrorMsg=%lf",ErrorMsg,SqlState,iErrorMsg);    
       MessageBox(0,s,&table,0);
      
      i++;
   }

Вот что получил:
[quote]
szErrorMsg=Обновление невозможно; установлена блокировка пользователем “admin”
szSqlState=HY000
pcbErrorMsg=0.00000
[/quote]
Короче тоже самое.
ИЗ МСДН
[quote]
HY000 General error An error occurred for which there was no specific SQLSTATE and for which no implementation-specific SQLSTATE was defined. The error message returned by SQLGetDiagRec in the MessageText buffer describes the error and its cause.
[/quote]
Стоит отметить, что с ОДБЦ я работаю впервые, так что может стоит искать глупую ошибку или все таки надо разграничивать пользование критическим ресурсом? Если второе, то как лучше, есть какая-нибудь функция, которая возвращает готовность БД или там чего еще, для того, чтобы была возможность вставлять запрос.
Re[8]: Win API & ODBC (отказ в создании записи )
От: NdF  
Дата: 14.11.05 13:33
Оценка:
Мужики, может део в транзакции? Тогда что и как исправить? Что никто с этим не сталкивался?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.