Работа с БД в многопотоке - как заставить каждый поток работать только со своим соединением ?

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Приветствую.

При работе с БД в зенке столкнулся с очень неприятной вещью, а именно периодической сменой CONNECTION ID в рамках потока ...
Итак, допустим шаблон состоит из нескольких кубиков для работы с БД, между ними есть какая-то логика (сейчас не важно какая). Допустим первый кубик создает соединение с БД с идентификатором 1111, второй и последующие кубики уже могут подхватить не это соединение, а соединение от первого кубика из вообще другого потока зенки!

Что это означает на практике?

Допустим у нас есть такая логика:
1) лочим таблицы
2) делаем запрос на получение каких-то данных
3) как-то, допустим, работаем с полученными из бд данными
4) записываем/обновляем данные в бд
5) разлочиваем таблицы

В одном кубике все эти операции не выполнить, соответственно задача разбивается на несколько кубиков ... В результате при попытке разлочить таблицу мы уже можем иметь совершенно другой connection id, а не тот при котором лочили (!) ... соответственно unlock не сработает

Или другая ситуация: один поток залочил таблицы и делает долгий и тяжелый запрос, а паралелльный поток зенки подхватил соединение первого и в результате вообще не имеет доступа к каким-либо таблицам так как: Пока клиент удерживает явную блокировку, он не может использовать другие таблицы, поэтому блокировать нужно сразу все что понадобится (одним выражением), так как повторное использование оператора LOCK TABLES отменяет сделанные ранее блокировки.

Вот для примера небольшой шаблон, который генерит случайную строку (идентификатор потока в ZP) и просто с некоторой задержкой делает запрос к БД получая CONNECTION _ID ...

2018-08-08_07-30-45.png
Запускаем его допустим в 2 потока и смотрим лог:

ZennoPoster_2018-08-08_07-32-11.png
Тут мы видим что поток с идентификатором 69GJD при первом вызове кубика работы с БД имел CONNECTION ID = 2270, а следющие 2 кубика работы с БД (в этом же потоке 69GJD) уже использовали CONNECTION ID полученный в другом потоке зеннопостера (2269)... с другим потоком все то же самое

Отсюда вопрос: можно ли как-то заставить в рамках потока ZP использовать одно и то же соединение (до таймаута), а не подхватывать соединения созданные другими потоками ???

p.s у меня зенка старая 5.11.4, может в новых версиях как-то по другому?
 
Последнее редактирование:

Alex733

Client
Регистрация
27.11.2017
Сообщения
330
Благодарностей
243
Баллы
43
Для mysql должно помочь: перевести бд из myisam в innodb (предварительно сделав back up БД) и использовать select for update.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Итак InnoDB, но тип хранилища на соединение выбираемое из пула соединений никак не влияет!
SELECT FOR UPDATE использовать можно, НО как правило (за редким исключением) между SELECT и UPDATE нужно вставить еще какую-то логику, обработку полученных селектом данных к примеру ... и в этом случае SELECT FOR UPDATE никак не поможет.

У меня, например, идет лок нескольких таблиц, запрашиваются данные из одной, идет обрабатка этих данных на c#, потом в результате этой обработки остаются id которые нужно пометить в другой таблице соответствующим образом ... то есть без вот этой вот дополнительной обработки данных между селектом и апдейтом вообще никак не обойтись ... а в результате лок с таблиц не снимается и начинаются всякие нехорошие вещи ;-)
 

Alex733

Client
Регистрация
27.11.2017
Сообщения
330
Благодарностей
243
Баллы
43
Транзакции пробовали? Т.е. между select for update и update делать проверку данных, если все в порядке сделать commit, если нет, то откатить транзакцию (rollback).
Или покопать в сторону настроек mysql.
Возможно стоит, какая-то настройка, которая позволяет повторно использовать открытые соединения.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
В том то и дело что START TRANSACTION может быть выполнена используя одно соединение, а когда дело дойдет до комита, то будет использоваться другое соединение ....

Нет проблем если все делать одним кубиком работы с БД (вставлять туда сразу несколько запросов), он гарантировано будет юзать одно соединение, но тогда не вставить свою логику между селектом и апдейтом (а без нее никак)
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
В общем хочется что бы каждый поток зеннопостера гарантировано создавал свое новое соединение и все кубики работы с БД в рамках текущего потока работали именно с ним ... если таймаут кончится, что бы создавалось новое, а не бралось от других потоков
 

Alex733

Client
Регистрация
27.11.2017
Сообщения
330
Благодарностей
243
Баллы
43
Я использую для БД php (openserver), поэтому, возможно у меня и не возникало такой проблемы. Т.е. вся логика между запросами находится в одном кубике C#. Скиньте мне проект, который у в 1-м посте. Попробую у себя на 5.18.0.0
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Я то же опенсервер юзаю!

В php, ксати, ты сам управляешь соединением ... там логика такая: создал соединение и получил его идентификатор, дальше делая запросы ты передаешь в функции идентификатор соединения и запросы ганатировано уходят именно в рамках этого одного соединения ...
то есть делаешь
$id = mysql_connect(....)
mysql_query("lock ...",$id);
mysql_query("селект ...",$id);
логика какя-то
mysql_query("апдейт ...",$id);
mysql_query("unlock tables",$id);

Шаблон прикрепил!
Запускать соответственно так:
кол-во потоков = 2
сколько делать = 2
смотрим лог ... иногда нужно запустить таким образом несколько раз что бы это увидеть что в рамках одного потока разные кубики работы с БД используют разные соединения
Ну и в кубиках работы с БД указан localhost, юзер root, пустой пароль, имя бд mydb ... как минимум название БД нужно поменять на любую из тех что у вас имеется
 

Вложения

Alex733

Client
Регистрация
27.11.2017
Сообщения
330
Благодарностей
243
Баллы
43
Пока не пробовал, но глянув на код появилась мысль, которая может помочь. Переведите запросы к БД в C# код (у меня переводится в правой кнопкой мыши) и засуньте всю логику в один кубик.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Пока не пробовал, но глянув на код появилась мысль, которая может помочь. Переведите запросы к БД в C# код (у меня переводится в правой кнопкой мыши) и засуньте всю логику в один кубик.
Я в кубиках это привел просто для наглядности ... на самом деле у меня создан в общем коде свой класс DB и созданы несколько методов-оберток под это дело ... я то же юзаю все это в c# коде

То есть у меня все это на самом деле выглдит примерно так:

DB db = new DB("localhost","root","","mydb");
db.query("LOCK TABLES ...");
var data = db.getAll("SELECT .... LIMIT 100");
тут какая-то работа с data выполняется
db.query("UPDATE ...");
db.query("UNLOCK TABLES");
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Попробую привлечь внимание к этом вопросу админов/разработчиков ... уж кто если не они знают можно ли как-то победить данную проблему!
@AShaggy , @darkdiver , может быть Вы прольете свет по данному вопросу?
 

Alex733

Client
Регистрация
27.11.2017
Сообщения
330
Благодарностей
243
Баллы
43
Пример из 1-го поста у меня работает, так же как у вас.
Попробуйте interactive_timeout поставить 28800 в my.cnf
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
В общем экспериментировал по всякому и пришел к выводу что проще свой класс переписать без использования кода из стандартного кубика ж) Сделать открытие соединения в конструкторе и специальный метод close для его закрытия, ну и запретить pooling конечно ... тогда каждый поток будет юзать строго свой коннект сколько бы запросов из него не отправлялось и можно будет юзать свою логику между, например, стартом транзакции и комитом. Да, придется конечно в ExternalAssemblies таскать MySql.Data.dll , но других вариантов пока не вижу.
 

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