Собственно есть программка на С++( назовем ее create_task), которая тянет данные из таблички tasks(mssql). Эта табличка постоянно меняется. За минуту может добавиться от 10 до 100 новых записей. create_task кидает по таймауту в 5 сек запрос к табличке tasks(ищет записи с time_start = тгдд), и считав данные создает поток, в потоке меняет состояние записи в create_task(time_start = текущая дата) и выполняет некоторые вычисления, которые длятся от 2 секунд до 30 мин. По окончании вычислений удаляет запись из create_task. Все хорошо и нормально работает, однако запустив несколько копий create_task происходит дублирование, т.е. для одной и той же записи в tasks запускается по одному потоку в разных копиях create_task. Происходит это не всегда, а тогда, когда первая копия create_task считала данные,создала поток но еще не изменила статус записи, а вторая копия уже считала данные.
вот код
...
//для работы с com
CoInitialize(NULL);
//база данных
ADODB::_ConnectionPtr m_conn = 0;
ADODB::_RecordsetPtr m_rs = 0;
//бесконечный цикл для процесс
while (TRUE)
{
HRESULT hr;
try
{
hr = m_conn.CreateInstance(__uuidof(ADODB::Connection));
if FAILED(hr) {
throw _com_error(hr);
}
m_conn->CursorLocation = ADODB::adUseClient;
m_conn->Open(cons, L"", L"", ADODB::adConnectUnspecified);
//m_conn->PutIsolationLevel( ADODB::adXactReadUncommitted );
hr = m_rs.CreateInstance(__uuidof(ADODB::Recordset));
if FAILED(hr)
{
throw _com_error(hr);
}
//char sql_query[200] = "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;\0 BEGIN TRANSACTION ;\0 ";
//m_rs->Open(sreq_param, m_conn.GetInterfacePtr(), ADODB::adOpenStatic, ADODB::adLockReadOnly, ADODB::adCmdUnspecified);
//запрос на получение задач на выполнение
char sreq_param[200] = "SELECT t.id, t.user_id, t.reports_id, r.name FROM tasks t, reports r WHERE time_start is NULL AND t.reports_id = r.id;\0";
m_rs->Open(sreq_param, m_conn.GetInterfacePtr(), ADODB::adOpenStatic, ADODB::adLockReadOnly, ADODB::adCmdUnspecified);
while ( !m_rs->ADOEOF)
{
//создаем поток и меняем значение в записи таблицы
}
//char sql_query2[200] = "COMMIT TRANSACTION ;\0 ";
//m_rs->Open(sql_query2, m_conn.GetInterfacePtr(), ADODB::adOpenStatic, ADODB::adLockReadOnly, ADODB::adCmdUnspecified);
m_rs->Close();
m_conn->Close();
}
catch(...)
{
printf("Unhandled exception...");
};
Sleep(5000);
}
...
Копал в сторону SET TRANSACTION ISOLATION LEVEL SERIALIZABLE и BEGIN TRANSACTION / COMMIT TRANSACTION Попытки использования оформлены ввиде комментария. Я не понимаю как их использовать и как они работают.
Если одна копия create_task запустит BEGIN TRANSACTION а потом вторая, как будут себя вести запросы? Какова область видимости у BEGIN TRANSACTION( если например в потоке я сделаю коннект к БД)? Возможно ли методами ADODB заблокировать таблицу?
Очень большая просьба "разжевать " вопрос. Заранее благодарю.