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

Nike59

Client
Регистрация
05.08.2011
Сообщения
122
Благодарностей
122
Баллы
43

Corwin09

Client
Регистрация
02.11.2020
Сообщения
6
Благодарностей
0
Баллы
1
Привет, всем! Может кто поделиться RecaptchaSolution.dll?
 

one

Client
Регистрация
22.09.2015
Сообщения
6 833
Благодарностей
1 275
Баллы
113

Corwin09

Client
Регистрация
02.11.2020
Сообщения
6
Благодарностей
0
Баллы
1
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
Подскажите как реализовать следующую конструкцию при помощи данной библиотеки(или любым другим методом)?
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.
При этом всё это нужно лочить, чтобы можно было работать многопотоке.
Помогите, а то уже мозг кипит
 
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
Что я делаю не так?
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.
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
Что я делаю не так?
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
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
опять затык( не могу вставить переменную с названием таблицы в код блокировки
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]
Сейчас вроде всё делаю верно. Кто-нибудь может подсказать как это победить?
 

volody00

Client
Регистрация
06.09.2016
Сообщения
918
Благодарностей
953
Баллы
93
опять затык( не могу вставить переменную с названием таблицы в код блокировки
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

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
опять затык( не могу вставить переменную с названием таблицы в код блокировки
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
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
Запоздалая благодарность автору за статью! Но как известно, лучше поздно чем никогда)

Сейчас расскажу вам грустную историю:
Месяц назад я на притяжение 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"- Название базы данных

Как мне кажется я попробовал уже все варианты.
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 719
Баллы
113
Запоздалая благодарность автору за статью! Но как известно, лучше поздно чем никогда)

Сейчас расскажу вам грустную историю:
Месяц назад я на притяжение 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
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
может так ?
$"{tabl} WRITE"
Ты не представляешь как мне стыдно:bh: Хоть убейте, не помню что я уже это спрашивал. Написал модераторам, чтобы удалили этот позор.
Так стыдно, хоть на форуме не появляйся
Последнее время было куча проблем, башка вообще не своя
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 719
Баллы
113
Ты не представляешь как мне стыдно:bh: Хоть убейте, не помню что я уже это спрашивал. Написал модераторам, чтобы удалили этот позор.
Так стыдно, хоть на форуме не появляйся
Последнее время было куча проблем, башка вообще не своя
ничего тут такого нет. все мы забываем , кто то больше кто то меньше.
как то тут на форуме увидел скрины проги AllMyNotes Organizer и теперь тоже все пишу в нее. все снипеты, идеи, контакты клиентов... ну вот прям все. жить и разрабатывать стало проще :-)
 
  • Спасибо
Реакции: KolkaPetkinSyn
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
ничего тут такого нет. все мы забываем , кто то больше кто то меньше.
как то тут на форуме увидел скрины проги AllMyNotes Organizer и теперь тоже все пишу в нее. все снипеты, идеи, контакты клиентов... ну вот прям все. жить и разрабатывать стало проще :-)
Спасибо посмотрю, что там за органайзер
 
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
Чтобы из таблицы не брались дубли в моём случае нужно блокировать на чтение. Но если я так делаю я не могу поменять флаг, чтобы отметить строку как в работе
Выполнение действия CSharp OwnCode: Блокировка таблиц. Table 'cop' was locked with a READ lock and can't be updated
Как нужно поступить в этом случае?
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
Чтобы из таблицы не брались дубли в моём случае нужно блокировать на чтение. Но если я так делаю я не могу поменять флаг, чтобы отметить строку как в работе

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

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

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

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

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(); //закрываем сессию
 
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
В коде выше потерялась строка открытие соединения, но это произошло уже в ходе экспериментов. Найти решение проблемы не могу.
Блокировка на запись работает, блокировка на чтение нет(
Может автор что-то забыл добавить в общий код? Кто пользуется наработками, подскажите. Автора уже давно не было на форуме
 
Регистрация
23.03.2015
Сообщения
1 218
Благодарностей
751
Баллы
113
Поменял:
cmd.DbLock($"{tabl} READ");
на
cmd.CommandText = $"LOCK TABLES {tabl} READ;";
cmd.ExecuteNonQuery();

Никакого эффекта, таже самая ошибка
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
Поменял:
cmd.DbLock($"{tabl} READ");
на
cmd.CommandText = $"LOCK TABLES {tabl} READ;";
cmd.ExecuteNonQuery();

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

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

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

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
Я думал что блокировка ещё для других потоков.
Так и есть.

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

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

Попробуйте поставить WRITE и потестировать.
 
  • Спасибо
Реакции: rol и KolkaPetkinSyn

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
READ — блокирует таблицу для чтения. Все клиенты могут получать данные одновременно, но никто не может их изменять, даже тот клиент, который установил блокировку.

WRITE — блокирует таблицу для записи. Только клиент установивший блокировку может получать и изменять данные.
 
  • Спасибо
Реакции: KolkaPetkinSyn

prostors

Client
Регистрация
16.12.2020
Сообщения
1 015
Благодарностей
33
Баллы
48
пробовал блокировать таблицу, как указано в теме - при запуске одинаковых кубиков на разных версиях pm на пк и удалёнке - срабатывают правки - хз что блокируется
пробовал блокировать строки - for update, LOCK IN SHARE MODE - игнорятся оба
 

prostors

Client
Регистрация
16.12.2020
Сообщения
1 015
Благодарностей
33
Баллы
48
при прописанных for update, LOCK IN SHARE MODE должны ли меняться какие-то статусы в таблице?
хочу проверить, выполняется ли блокировка на уровне MySQL
 

Castaneda

Client
Регистрация
24.05.2019
Сообщения
872
Благодарностей
299
Баллы
63
Подскажите как изменить тестовый шаблон, чтобы соединение создавалось один раз при старте проекта и закрывалось на good/ban end.

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

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

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

подскажите как поправить
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
395
Благодарностей
126
Баллы
43
Подскажите как изменить тестовый шаблон, чтобы соединение создавалось один раз при старте проекта и закрывалось на 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

Castaneda

Client
Регистрация
24.05.2019
Сообщения
872
Благодарностей
299
Баллы
63
Так не желательно делать.
Одна из причин.
Вы создали подключение, получили данные из БД, потом их обрабатываете к примеру 3 минуты, а за это время mysql сервер из-за простоя разорвёт соединение, не спрашивая и не предупреждая клиента.
И когда клиент опять запросит данные, то получит ошибку подключения.

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

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

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