:: Visual Foxpro, Foxpro for DOS
Курсорадаптер и max_user_connections
Sandwich
Автор

Сообщений: 137
Дата регистрации: 08.02.2014
Здравствуйте
Сделал приложение, работающее с БД MySQL на веб-сервере.
Использую курсорадаптеры.
Все работало прекрасно, пока пользователь был один.
Возникла необходимость работы с нескольких компьютеров.
При запуске программы на 4-5 по счету компьютере получаю от ODBC - ... already has more then "max_ user_connections" active connections
В настройках MySQl max_ user_connections = 100 (хостер не дает право изменять).
Начал следить за подключениями через консоль MySQL:
1. Без запущенной программы - 8-12 активных подключений
2. Каждый запущенный экземпляр программы прибавляет еще ~20
Соответственно лимит быстро исчерпывается.
На этой строке решил сделать паузу, потому что понял, что у меня 12 КАДов и для каждого из них создаю своё подключение.
Исправил - все 12 "посадил" на один SQLSTRINGCONNECT.
Ситуация немного улучшилась: каждый экземпляр программы добавляет ~12 подключений (итого можно запустить 6-7 экземпляров)
Дальше понял, что из 12 таблиц мне нужно изменять только 2, остальные 10 - только получение данных. Поэтому для этих 10 КАДов после cad.cursorfill() поставил cad.destroy().
Количество подключений от этого не изменилось.
В итоге 2 вопроса:
1. Почему в ситуации когда 12 КАДов сидят на одном соединении, MySQl показывает 12 подключений?
2. Как "отключить" 10 "readonly" КАДов (дабы сократить количество активных подключений)?
Ratings: 0 negative/0 positive
Re: Курсорадаптер и max_user_connections
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Значит они НЕ висят "на одном соединении".
Стандартно делается один SQLSTRINGCONNECT() с флагом shared - полученный хендл напрямую НЕ используется, от него создаются новые хендлы при помощи SQLCONNECT. Эти новые хендлы и используются в курсорадаптерах, при этом в destroy их следует закрывать.
При отладке можно использовать ASQLHANDLES() - без 2-го параметра и с ним, чтобы смотреть какие же существуют соединения и какие statement handles их используют.
P.S. "отключать" ничего не надо - statement handle для "завершённой" выборки не должен потреблять серверных ресурсов (а клиентскими можно пренебречь - сам курсор наверняка гораздо больше памяти потребляет чем блок метаданных в odbc драйвере) - стоит лишь позаботится о синхронном режиме работы с соединением, для чего в курсорадаптере поставить fetchsize=-1 и отключить тем самым "прогрессивную" выборку - когда по сути одновременно фокс пытается данные закачивать в разные адаптеры.


------------------
WBR, Igor




Исправлено 1 раз(а). Последнее : Igor Korolyov, 05.05.19 22:02
Ratings: 0 negative/0 positive
Re: Курсорадаптер и max_user_connections
Sandwich
Автор

Сообщений: 137
Дата регистрации: 08.02.2014
Результаты мучений:
Вариант 1
lnCon=SQLSTRINGCONNECT() без shared
У 12-ти КАДов .DataSourse=lnCon
ASQLHANDLES выдает массив из 13 значений (от 1 до 13, видимо 1+12)
Вариант 2
lnCon=SQLSTRINGCONNECT() с shared
lnCon1=SQLCONNECT(lnCon)
lnCon2=SQLCONNECT(lnCon)
...
У 12-ти КАДов .DataSourse=lnConN
ASQLHANDLES выдает массив из 25 значений (от 1 до 25, видимо 1+2*12)
У КАДов.DataSourse идут 3,5,7...25
Соответственно после закрытия этих соединений в destroy, остаются какие-то дополнительные соединения 1,2,4,6...24

?
Ratings: 0 negative/0 positive
Re: Курсорадаптер и max_user_connections
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Изучай код (кады, поди от какого-то класса наследуются, может там есть свой код управления соединениями, может в формах использующих эти кады что-то делается с их DataSource, или если это "мастером" созданные кады - там тоже будет код управления соединением) - похоже что кто-то открывает и не закрывает дополнительные соединения. Скажем при работе с ораклом мы специально делали отдельные хендлы (но не соединения) для InsertCmdDataSource/UpdateCmdDataSource/DeleteCmdDataSourceType - через один общий с некоторыми версиями клиентских компонент были проблемы - так что один CAD у нас по 4 statement handle использовал (а можно и больше, там ещё на рефреш и на извлечение мемо-полей можно отдельный хендл задать). Конечно же они все закорывались в destroy адаптера.

Проверь для хендлов (пока ещё все 25 живые) 2,4,6... их SQLGETPROP(..,"ODBChdbc") - это "настоящий" хендл соединения - по идее он должен совпадать для всех хендлов порождённых от одного начального shared. Ну и ASQLHANDLES(...,1) и ASQLHANDLES(...,2) покажут общее это соединение или нет.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Курсорадаптер и max_user_connections
Sandwich
Автор

Сообщений: 137
Дата регистрации: 08.02.2014
Чем дальше в лес (или влез), тем ...
Получается такая картина:
В билдере создаю кад - cad_name. Указываю там Use connection string = 'Строка соединения №1'.
Затем код
lnCon=SQLSTRINGCONNECT('Строка соединения №1 или №2') && без shared
=ASQLHANDLES(ss) && одно соединение (№1)
cad1=createobject('cad_name')
=ASQLHANDLES(ss) && два соединения (№1 и №2)
cad1.DataSourse=lnCon && cad1 "переключен" на соединение №1
В итоге понятно:
билдер в cad1.init прописывает
This.DataSource = sqlstringconnect('Строка соединения №1')
В итоге не понятно:
1. Как до создания cad1 задать ему нужное (не designtime) значение DataSource?
2. Как использовать галочку use connection settings in builder only в билдере?
Ratings: 0 negative/0 positive
Re: Курсорадаптер и max_user_connections
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Сложно сказать, я как-то построителем не пользовался никогда У нас были свои базовые классы для cad, и свои генераторы (чтобы мутотень со списокм полей и базовыми запросами не руками прописывать, а только потом править, если надо).

Sandwich
1. Как до создания cad1 задать ему нужное (не designtime) значение DataSource?
ДО создания - никак. Да и не нужно это. Источник данных может прописываться из Init адаптера (как это делает построитель, только НЕ его кодом, а своим - тут то и прочувствуешь необходимость написания своего класса cad, от которого будут унаследованы все другие адаптеры), или в инфраструктурном коде использующем адаптеры (том где и прописан createobject("cadSomeData") - после этих Create но до вызова CursorFill и нужно задать DataSource). Помещать адаптеры в DE не советую, малоуправляемо и сложно в нормальном ООП стиле оформить. Для начала простейший вариант с созданием объекта-коллекции в Load формы и добавлением в неё нужных адаптеров (опять же всё кодом в Load - добавил, вызвал CursorFill - возможно с флажком NoData, если параметры ограничивающие выборки известны будут лишь позже, в Init формы или вообще будут браться из полей ввода на ней).


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Курсорадаптер и max_user_connections
Sandwich
Автор

Сообщений: 137
Дата регистрации: 08.02.2014
Igor Korolyov
ДО создания - никак.
Успел разобраться сам, но не успел написать здесь.
А построитель работает так: если НЕ ставишь галку use connection settings in builder only, то он формирует такой Init
*** Setup code: DO NOT REMOVE
local llReturn
do case
case not pemstatus(This, '__VFPSetup', 5)
This.AddProperty('__VFPSetup', 0)
case This.__VFPSetup = 1
This.__VFPSetup = 2
case This.__VFPSetup = 2
This.__VFPSetup = 0
return
endcase
set multilocks on
llReturn = dodefault()
*** End of Setup code: DO NOT REMOVE
*** Select connection code: DO NOT REMOVE
***<DataSource>
This.DataSource = sqlstringconnect([DRIVER=MySQL ODBC 5.3 ANSI Driver;USER=88888_544;PORT=3306;PASSWORD=8] + ;
[8888;SERVER= 888888.timeweb.ru;DATABASE=88888_544;OPTION=3;STMT=S] + ;
[ET NAMES utf8;])
***</DataSource>
*** End of Select connection code: DO NOT REMOVE
*** Setup code: DO NOT REMOVE
if This.__VFPSetup = 1
This.__VFPSetup = 2
endif
return llReturn
*** End of Setup code: DO NOT REMOVE
а если поставить эту галку, то Init формируется без This.DataSource = ...
Спасибо за помощь!
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 33 (Гостей: 33)

© 2000-2024 Fox Club 
Яндекс.Метрика