Помогите с Java потоками или исполнителями: выполнение нескольких выборов MySQL, вкладывает и обновляется однократно
-
22-10-2019 - |
Вопрос
Я пишу приложение для анализа базы данных MySQL, и мне нужно выполнить несколько DMLS с однократным образом; Например:
// In ResultSet rsA: Select * from A;
rsA.beforeFirst();
while (rsA.next()) {
id = rsA.getInt("id");
// Retrieve data from table B: Select * from B where B.Id=" + id;
// Crunch some numbers using the data from B
// Close resultset B
}
Я объявляю множество объектов данных, каждый со своим собственным соединением с базой данных, которая, в свою очередь, вызывает несколько методов для анализа данных. Проблема состоит в том, что все потоки используют одно и то же соединение, поэтому все задачи бросают, кроме: «Заблокировать тайм -аут ожидания превышен; попробуйте перезапустить транзакцию»
Я полагаю, что есть способ написать код таким образом, чтобы любой заданный объект имел свое собственное соединение и выполняет необходимые задачи, независимые от любого другого объекта. Например:
DataObject dataObject[0] = new DataObject(id[0]);
DataObject dataObject[1] = new DataObject(id[1]);
DataObject dataObject[2] = new DataObject(id[2]);
...
DataObject dataObject[N] = new DataObject(id[N]);
// The 'DataObject' class has its own connection to the database,
// so each instance of the object should use its own connection.
// It also has a "run" method, which contains all the tasks required.
Executor ex = Executors.newFixedThreadPool(10);
for(i=0;i<=N;i++) {
ex.execute(dataObject[i]);
}
// Here where the problem is: Each instance creates a new connection,
// but every DML from any of the objects is cluttered in just one connection
// (in MySQL command line, "SHOW PROCESSLIST;" throws every connection, and all but
// one are idle).
Можете ли вы указать мне правильное направление?
Спасибо
Решение 2
После некоторого времени разрыва мозга я понял свои собственные ошибки ... Я хочу поставить эти новые знания, так что ... вот я иду
Я сделал очень большая ошибка Объявив подключение objet как статический объект в моем коде ... так что, очевидно, несмотря на то, что я создал новое соединение для каждого нового объекта данных, который я создал, каждая транзакция прошла через одно статическое соединение.
С этой первой проблемой исправлена, я вернулся к дизайнерскому столу и понял, что мой процесс был:
- Прочитайте идентификатор из таблицы ввода
- Возьмите блок данных, связанных с идентификатором, прочитанным на шаге 1, хранятся в других входных таблицах
- Числа хруста: прочитайте связанные входные таблицы и обрабатывайте данные, хранящиеся в них
- Сохранить результаты в одной или нескольких выходных таблицах
- Повторите процесс, пока у меня есть идентификаторы в таблице ввода
Просто используя выделенное соединение для чтения ввода и выделенное соединение для написания вывода, производительность моей программы увеличилась ... но мне нужно было намного больше!
Мой первоначальный подход к шагам 3 и 4 заключался в том, чтобы сохранить в выводе каждый из результатов, как только они у меня были ... но я нашел лучший подход:
- Прочитайте входные данные
- Хрустят числа и поместите результаты в кучу очередей (по одному для каждой выводной таблицы)
- Отдельный поток проверяется каждую секунду, если есть данные в любой из очередей. Если в очереди есть данные, напишите их в таблицы.
Таким образом, разделив входные и выходные задачи, используя различные соединения, и перенаправляя выходной вывод процесса на очередь, и, используя выделенный поток для задач вывода хранилища, я наконец достиг того, что хотел: многопоточное выполнение DML!
Я знаю, что есть лучшие подходы к этой конкретной проблеме, но эта работает довольно хорошо.
Так что ... если кто -то застрял с такой проблемой ... Я надеюсь, что это поможет.
Другие советы
Я думаю, что проблема в том, что вы смешали много среднего уровня, транзакции и постоянной логики в одном классе.
Если вы имеете дело напрямую с результатами, вы не думаете о вещах очень ориентированным на объект.
Вы умны, если вы можете выяснить, как заставить базу данных сделать некоторые из ваших вычислений.
Если нет, я бы порекомендовал поддерживать открытые соединения в течение минимального времени. Откройте соединение, получите результаты, сочините его в объект или структуру данных, закройте результаты и соединение в локальном объеме и верните сопоставленную структуру объекта/данных для обработки.
Вы сохраняете настойчивость и логику обработки отдельно. Вы спасаете себя большим горем, сохраняя недолгие связи.
Если хранимое решение для процедуры медленное, оно может быть связано с плохой индексацией. Другое решение будет работать одинаково плохо, если не хуже. Попробуйте запустить план объяснения и посмотрите, используют ли какие -либо из ваших запросов сканирование таблицы. Если да, у вас есть несколько индексов, которые нужно добавить. Это также может быть связано с большими откатами в журналах, если ваши транзакции будут продолжительными. Есть многое, что вы могли бы и должны сделать, чтобы убедиться, что вы сделали все возможное с решением, которое у вас есть перед переключением. Вы можете пойти на большие усилия и при этом не учитывать основную причину.