2 место Работа с MySql в многопотоке. Блокировка таблиц. Получение id добавленной записи.

Привет, всем! Может кто поделиться RecaptchaSolution.dll?
 
Подскажите как реализовать следующую конструкцию при помощи данной библиотеки(или любым другим методом)?
SQL:
Развернуть Свернуть Копировать
LOCK TABLES tabl WRITE;
SELECT * FROM tabl WHERE op = '' AND city = 'minsk' LIMIT 1;
UPDATE tabl SET op = '1' WHERE user = '{-Variable.id-}';
UNLOCK TABLES;
Есть таблица с тремя колонками: 'user' 'city' 'op'
нужно взять строку с определенным параметром 'city' и пустым 'op', тем самым получив значение 'user' и установить в 'op' 1.
При этом всё это нужно лочить, чтобы можно было работать многопотоке.
Помогите, а то уже мозг кипит
 
Что я делаю не так?
C#:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project);
var cmd = sqlConn.Cmd();

//открываем сессию
cmd.Connection.Open();

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.DbLock("tabl WRITE");

//выполняем произвольное количество комманд в рамках сессии. Другие потоки не имеют доступ к БД пока она заблокирована
cmd.CommandText = String.Format("SELECT * FROM tabl WHERE op = '' AND cms = 'minsk' LIMIT 1;");
var reader = cmd.ExecuteReader();

while (reader.Read())
{
    string dbuser = reader["user"].ToString();
    string dbcity = reader["city"].ToString();
    string dbop = reader["op"].ToString();

    project.SendInfoToLog(string.Format("user: {0}, city: {1}, op: {2}", dbuser, dbcity, dbop));
}

//разблокировка всех таблиц
cmd.DbUnLock();


//закрываем сессию
cmd.Connection.Close();

ошибка:
Код:
Развернуть Свернуть Копировать
Выполнение действия CSharp OwnCode: Блокировка таблиц. There is already an open DataReader associated with this Connection which must be closed first.
 
Что я делаю не так?
C#:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project);
var cmd = sqlConn.Cmd();

//открываем сессию
cmd.Connection.Open();

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.DbLock("tabl WRITE");

//выполняем произвольное количество комманд в рамках сессии. Другие потоки не имеют доступ к БД пока она заблокирована
cmd.CommandText = String.Format("SELECT * FROM tabl WHERE op = '' AND cms = 'minsk' LIMIT 1;");
var reader = cmd.ExecuteReader();

while (reader.Read())
{
    string dbuser = reader["user"].ToString();
    string dbcity = reader["city"].ToString();
    string dbop = reader["op"].ToString();

    project.SendInfoToLog(string.Format("user: {0}, city: {1}, op: {2}", dbuser, dbcity, dbop));
}

//разблокировка всех таблиц
cmd.DbUnLock();


//закрываем сессию
cmd.Connection.Close();

ошибка:
Код:
Развернуть Свернуть Копировать
Выполнение действия CSharp OwnCode: Блокировка таблиц. There is already an open DataReader associated with this Connection which must be closed first.
Не проверял, но может нужно закрыть ридер перез разблокировкой таблиц.
C#:
Развернуть Свернуть Копировать
reader.Close();
 
  • Спасибо
Реакции: KolkaPetkinSyn
Не проверял, но может нужно закрыть ридер перез разблокировкой таблиц.
C#:
Развернуть Свернуть Копировать
reader.Close();
Спасибо, вы верно подсказываете и ещё было несколько ошибок
 
опять затык( не могу вставить переменную с названием таблицы в код блокировки
C#:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project);
var cmd = sqlConn.Cmd();
//Переменная с названием таблицы
string tabl = project.Variables["tabl"].Value;
//открываем сессию
cmd.Connection.Open();

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.DbLock("{0} WRITE", tabl);

...
Компиляция кода Ошибка в действии "CS1501" "No overload for method 'DbLock' takes 2 arguments". [Строка: 9; Cтолбец: 5]

Сейчас вроде всё делаю верно. Кто-нибудь может подсказать как это победить?
 
опять затык( не могу вставить переменную с названием таблицы в код блокировки
C#:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project);
var cmd = sqlConn.Cmd();
//Переменная с названием таблицы
string tabl = project.Variables["tabl"].Value;
//открываем сессию
cmd.Connection.Open();

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.DbLock("{0} WRITE", tabl);

...


Сейчас вроде всё делаю верно. Кто-нибудь может подсказать как это победить?
Если у тебя не ниже 7.2.0.0 можешь так (9 строка):

C#:
Развернуть Свернуть Копировать
cmd.DbLock($"{tabl} WRITE");
 
  • Спасибо
Реакции: KolkaPetkinSyn
опять затык( не могу вставить переменную с названием таблицы в код блокировки
C#:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project);
var cmd = sqlConn.Cmd();
//Переменная с названием таблицы
string tabl = project.Variables["tabl"].Value;
//открываем сессию
cmd.Connection.Open();

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.DbLock("{0} WRITE", tabl);

...


Сейчас вроде всё делаю верно. Кто-нибудь может подсказать как это победить?
C#:
Развернуть Свернуть Копировать
cmd.DbLock(string.Format("{0} WRITE", tabl));

// или
cmd.DbLock(tabl + " WRITE");

// или начиная с 7.2.0.0
cmd.DbLock($"{tabl} WRITE");
 
  • Спасибо
Реакции: KolkaPetkinSyn
Запоздалая благодарность автору за статью! Но как известно, лучше поздно чем никогда)

Сейчас расскажу вам грустную историю:
Месяц назад я на притяжение 3 дней тратил свободное время на создание кубика для работы с базой данных в многопотоке(с# и mysql знаю очень поверхностно). Кое-как осилил я этот труд и сделал прекрасный шаблончик на базе этого сниппета. Пару недели шаблон чик трудился верой и правдой, потом я переустановил Винду и до запуска шаблона руки не доходили. Параллельно делал несколько шаблонов схожей тематики и регулярно заглядывал в вышеуказанные шаблон, чтобы освежить в памяти и полученные знания и сделать по подобию.
Три дня назад решил, что хватит шаблону простаивать и надо запускать его в работу, но не тут-то было. По каким-то причинам весь C# сниппет был удалён. Я по матерился, но не стал отчаиваться. Сделал раз, сделаю и два. Второй раз будет проще, думал я. Вот наивный!
Уже 2 дня мучаюсь с одной проблемой, не могу в код передать название базы данных для блокировки из переменной шаблона. При том что точно помню что тогда делал так, как и сейчас.
Пожалуйста помогите, вообще не понимаю что не так!?
Проблемный кусок:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project); //Подключаемся к БД
var cmd = sqlConn.Cmd();
cmd.Connection.Open(); //открываем сессию
string tabl = project.Variables["tabl"].Value;

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.Parameters.AddWithValue("@tabl", tabl);
cmd.DbLock("@tabl WRITE");
    
cmd.DbUnLock(); //разблокировка всех таблиц
cmd.Connection.Close(); //закрываем сессию
Ошибка:
Выполнение действия CSharp OwnCode: Блокировка таблиц. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''com_es' WRITE' at line 1
"com_es"- Название базы данных

Как мне кажется я попробовал уже все варианты.
 
Запоздалая благодарность автору за статью! Но как известно, лучше поздно чем никогда)

Сейчас расскажу вам грустную историю:
Месяц назад я на притяжение 3 дней тратил свободное время на создание кубика для работы с базой данных в многопотоке(с# и mysql знаю очень поверхностно). Кое-как осилил я этот труд и сделал прекрасный шаблончик на базе этого сниппета. Пару недели шаблон чик трудился верой и правдой, потом я переустановил Винду и до запуска шаблона руки не доходили. Параллельно делал несколько шаблонов схожей тематики и регулярно заглядывал в вышеуказанные шаблон, чтобы освежить в памяти и полученные знания и сделать по подобию.
Три дня назад решил, что хватит шаблону простаивать и надо запускать его в работу, но не тут-то было. По каким-то причинам весь C# сниппет был удалён. Я по матерился, но не стал отчаиваться. Сделал раз, сделаю и два. Второй раз будет проще, думал я. Вот наивный!
Уже 2 дня мучаюсь с одной проблемой, не могу в код передать название базы данных для блокировки из переменной шаблона. При том что точно помню что тогда делал так, как и сейчас.
Пожалуйста помогите, вообще не понимаю что не так!?
Проблемный кусок:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project); //Подключаемся к БД
var cmd = sqlConn.Cmd();
cmd.Connection.Open(); //открываем сессию
string tabl = project.Variables["tabl"].Value;

//Блокируем таблицы: advertise на записть (WRITE) и phone на запись (WRITE)
cmd.Parameters.AddWithValue("@tabl", tabl);
cmd.DbLock("@tabl WRITE");
   
cmd.DbUnLock(); //разблокировка всех таблиц
cmd.Connection.Close(); //закрываем сессию
Ошибка:

"com_es"- Название базы данных

Как мне кажется я попробовал уже все варианты.
может так ?
$"{tabl} WRITE"
 
  • Спасибо
Реакции: KolkaPetkinSyn
может так ?
$"{tabl} WRITE"
Ты не представляешь как мне стыдно:bh: Хоть убейте, не помню что я уже это спрашивал. Написал модераторам, чтобы удалили этот позор.
Так стыдно, хоть на форуме не появляйся
Последнее время было куча проблем, башка вообще не своя
 
Ты не представляешь как мне стыдно:bh: Хоть убейте, не помню что я уже это спрашивал. Написал модераторам, чтобы удалили этот позор.
Так стыдно, хоть на форуме не появляйся
Последнее время было куча проблем, башка вообще не своя
ничего тут такого нет. все мы забываем , кто то больше кто то меньше.
как то тут на форуме увидел скрины проги AllMyNotes Organizer и теперь тоже все пишу в нее. все снипеты, идеи, контакты клиентов... ну вот прям все. жить и разрабатывать стало проще :)
 
  • Спасибо
Реакции: KolkaPetkinSyn
ничего тут такого нет. все мы забываем , кто то больше кто то меньше.
как то тут на форуме увидел скрины проги AllMyNotes Organizer и теперь тоже все пишу в нее. все снипеты, идеи, контакты клиентов... ну вот прям все. жить и разрабатывать стало проще :-)
Спасибо посмотрю, что там за органайзер
 
Чтобы из таблицы не брались дубли в моём случае нужно блокировать на чтение. Но если я так делаю я не могу поменять флаг, чтобы отметить строку как в работе
Выполнение действия CSharp OwnCode: Блокировка таблиц. Table 'cop' was locked with a READ lock and can't be updated
Как нужно поступить в этом случае?
 
Чтобы из таблицы не брались дубли в моём случае нужно блокировать на чтение. Но если я так делаю я не могу поменять флаг, чтобы отметить строку как в работе

Как нужно поступить в этом случае?
Блокируйте таблицу только на момент получения значения.

1. Заблокировали таблицу.
2. Получили запись.
3. Установили свой флаг (допустим 'busy'), чтобы никакой другой поток уже не взял эту запись.
4. Сняли блокировку таблицы.

И так каждый поток.

Когда отработали с этой записью, опять тот же цикл чтобы допустим установить для готовой записи флаг 'good'.
 
Блокируйте таблицу только на момент получения значения.

1. Заблокировали таблицу.
2. Получили запись.
3. Установили свой флаг (допустим 'busy'), чтобы никакой другой поток уже не взял эту запись.
4. Сняли блокировку таблицы.

И так каждый поток.

Когда отработали с этой записью, опять тот же цикл чтобы допустим установить для готовой записи флаг 'good'.
Так я вроде так и делаю. Вот код:
C#:
Развернуть Свернуть Копировать
Sql sqlConn = new Sql(project); //Подключаемся к БД
var cmd = sqlConn.Cmd();
string tabl = project.Variables["tabl"].Value;

//Блокируем таблицы:
cmd.DbLock($"{tabl} REAT");
//проверяем наличие заданий к выполнению (со статусом "execute"):
var reader = cmd.ExReader(String.Format("SELECT domain FROM {0} WHERE cms='wordpress' AND openreg=0 LIMIT 1;", project.Variables["tabl"].Value));
if(reader.HasRows) //проверяем имеются ли данные в ответе. Если имеются, то переходим к считыванию
{
    while (reader.Read()) // построчно в цикле (while) считываем данные. Получим максимум 1 строку, т.к. в запросе стоит LIMIT 1
    {
        string dbdomen = reader["domain"].ToString(); //получаем id строки в БД, чтобы потом поменять статус задания
        
        project.Variables["donor"].Value = dbdomen; //сохраняем link в переменную зеннопостера
        
    }
}
reader.Close();

//Обновление статуса. Выполняется только если было получено задание (если id не пустое!)
if(!string.IsNullOrEmpty(project.Variables["donor"].Value))
{
    //после получения задания необходимо поменять статус задания, чтобы другие потоки больше его не видели после разблокировки таблицы
    cmd.ExNonQ(String.Format("UPDATE {0} SET openreg = 1 WHERE domain = '{1}';",project.Variables["tabl"].Value, project.Variables["domain_tp_vr"].Value));
}
    
cmd.DbUnLock(); //разблокировка всех таблиц
cmd.Connection.Close(); //закрываем сессию
 
В коде выше потерялась строка открытие соединения, но это произошло уже в ходе экспериментов. Найти решение проблемы не могу.
Блокировка на запись работает, блокировка на чтение нет(
Может автор что-то забыл добавить в общий код? Кто пользуется наработками, подскажите. Автора уже давно не было на форуме
 
Поменял:
cmd.DbLock($"{tabl} READ");
на
cmd.CommandText = $"LOCK TABLES {tabl} READ;";
cmd.ExecuteNonQuery();

Никакого эффекта, таже самая ошибка
 
Поменял:
cmd.DbLock($"{tabl} READ");
на
cmd.CommandText = $"LOCK TABLES {tabl} READ;";
cmd.ExecuteNonQuery();

Никакого эффекта, таже самая ошибка
Так вы блокируете таблицу на чтение "READ" и пытаетесь внести изменения.
Блокируйте на "WRITE".

p.s. Не часто заглядываю.
 
Так вы блокируете таблицу на чтение "READ" и пытаетесь внести изменения.
Блокируйте на "WRITE".

p.s. Не часто заглядываю.
Я думал что блокировка ещё для других потоков.
Тем более, какая разница чтение или запись? Мне же нужно сначала взять а потом изменить, то есть сначала Прочитайте а потом записать. Это какой-то глюк.
При блокировке записи, в многопотоке почему-то получаются дубли
 
Я думал что блокировка ещё для других потоков.
Так и есть.

Тем более, какая разница чтение или запись? Мне же нужно сначала взять а потом изменить, то есть сначала Прочитайте а потом записать. Это какой-то глюк.
Никакого глюка.
Если вы блокируете READ то текущий поток и все остальные потоки могут только читать, но не могут изменять.
Вам же нужно изменять (то есть писать), значит блокировка должна быть WRITE.

При блокировке записи, в многопотоке почему-то получаются дубли
Если ставите WRITE блокировку то не должно быть дублей.
Если ставите READ блокировку, то в момент получения записи, у вас другие потоки тоже могут получить ту же запись.

Попробуйте поставить WRITE и потестировать.
 
  • Спасибо
Реакции: rol и KolkaPetkinSyn
READ — блокирует таблицу для чтения. Все клиенты могут получать данные одновременно, но никто не может их изменять, даже тот клиент, который установил блокировку.

WRITE — блокирует таблицу для записи. Только клиент установивший блокировку может получать и изменять данные.
 
  • Спасибо
Реакции: KolkaPetkinSyn
пробовал блокировать таблицу, как указано в теме - при запуске одинаковых кубиков на разных версиях pm на пк и удалёнке - срабатывают правки - хз что блокируется
пробовал блокировать строки - for update, LOCK IN SHARE MODE - игнорятся оба
 
при прописанных for update, LOCK IN SHARE MODE должны ли меняться какие-то статусы в таблице?
хочу проверить, выполняется ли блокировка на уровне MySQL
 
Подскажите как изменить тестовый шаблон, чтобы соединение создавалось один раз при старте проекта и закрывалось на good/ban end.

Мудрил с Context вот так:
project.Context["sqlConn"] = new Sql(project);

var sqlConn = project.Context["sqlConn"];
var cmd = sqlConn.Cmd();

но вылетает ошибка:
"MySql.Data.MySqlClient.MySqlCommand" не содержит определения для "ExReader"

подскажите как поправить
 
Подскажите как изменить тестовый шаблон, чтобы соединение создавалось один раз при старте проекта и закрывалось на good/ban end.

Мудрил с Context вот так:
project.Context["sqlConn"] = new Sql(project);

var sqlConn = project.Context["sqlConn"];
var cmd = sqlConn.Cmd();

но вылетает ошибка:
"MySql.Data.MySqlClient.MySqlCommand" не содержит определения для "ExReader"

подскажите как поправить
Так не желательно делать.
Одна из причин.
Вы создали подключение, получили данные из БД, потом их обрабатываете к примеру 3 минуты, а за это время mysql сервер из-за простоя разорвёт соединение, не спрашивая и не предупреждая клиента.
И когда клиент опять запросит данные, то получит ошибку подключения.

Это сделано на тот момент, если клиент упал не закрыв соединение.
И для оптимизации сервера, если не обращаются длительное время, то нет смысла занимать пул соединения.

p.s. У меня в одном большом проекте так сделано (с костылями), и это не хорошо, но там уже что-то менять поздно. Много придётся переделывать.
Кстати в C# подключение очень дешёвая операция, это только самое первое подключение чуть затратно (может пару секунд) остальные подключения мгновенные.
 
  • Спасибо
Реакции: sydoow и Castaneda
Так не желательно делать.
Одна из причин.
Вы создали подключение, получили данные из БД, потом их обрабатываете к примеру 3 минуты, а за это время mysql сервер из-за простоя разорвёт соединение, не спрашивая и не предупреждая клиента.
И когда клиент опять запросит данные, то получит ошибку подключения.

Это сделано на тот момент, если клиент упал не закрыв соединение.
И для оптимизации сервера, если не обращаются длительное время, то нет смысла занимать пул соединения.

p.s. У меня в одном большом проекте так сделано (с костылями), и это не хорошо, но там уже что-то менять поздно. Много придётся переделывать.
Кстати в C# подключение очень дешёвая операция, это только самое первое подключение чуть затратно (может пару секунд) остальные подключения мгновенные.

большое спасибо за разъяснение))
 

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)