Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2 3 4   вперед  Ctrl      все
 Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
Собственно столкнулся с проблемой такого плана

есть сущность в которой одно из полей сделано уникальным
есть метод который берет эти сущности и пишет в базу
и все бы хорошо,когда все это в однопоточном режиме- просто делаешь запрос в базу - смотришь есть ли там такое значение если есть то скипаешь и все,либо же кладешь все в какой то сет и проверяешь была ли уже такая запись или нет

Но вот когда ты сталкиваешься с многопоточкой - то получается полная печаль
сделал коллекцию
oncurrentSkipListSet<String> concurrentSkipListSet

но все равно получается не то ,что хочется
сам метод выглядит так
  if (list.get(0) instanceof List) {
      for (Object mail : list) {
        if (((String) ((List) mail).get(0)).isBlank()) continue;
        EMailingEmail email = new EMailingEmail();
//          var email =eMailingMailRepository.findByEmail((String) ((List) mail).get(0));
        if (concurrentSkipListSet.contains((String) ((List) mail).get(0))) {
          email = eMailingMailRepository.findByEmail((String) ((List) mail).get(0));
        } else {
          email.setEmail((String) ((List) mail).get(0));
          email.setName((String) ((List) mail).get(1));
          email.setUserId(idsMap.get(doc.getString("uid")));

          concurrentSkipListSet.add((String) ((List) mail).get(0));
          eMailingMailRepository.save(email);
        }

        if (mailList.contains(email.getEmail())) continue;
        mailList.add(email.getEmail());


и получаю NullPointer в строчке if (mailList.contains(email.getEmail())) continue;
26 апр 21, 15:24    [22314517]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
[quot asv79#22314517]
        if (concurrentSkipListSet.contains((String) ((List) mail).get(0))) {
          email = eMailingMailRepository.findByEmail((String) ((List) mail).get(0));
      



я так понимаю что проблема вот тут - в коллекци этот емайл уже есть,но записаться в бд не успело? и получается объекту присваивается null
при дебаге в переменных email == null
но если сделать evaluate expression этой строчки eMailingMailRepository.findByEmail((String) ((List) mail).get(0)) будет найдено значение

может туда thread.sleep на 10-20 милисекунд или не в этом дело?
26 апр 21, 15:34    [22314528]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
Stanislav Bashkyrtsev
Member

Откуда: СПб
Сообщений: 137
Очень много кастов, сложно понимать что тут происходит.. Еще и закомментирована строка. Было бы здорово показывать тут чистый код, без лишнего.

Если бросается NPE, то либо email null, либо mailList. Видимо здесь null возвращается:
          email = eMailingMailRepository.findByEmail((String) ((List) mail).get(0));
Т.е. в concurrentSkipListSet элемент есть, а в базе уже нет. Добавь еще проверку на null.

А в целом - оправдано ли то, что ты дублируешь БД состояние в памяти?

Сообщение было отредактировано: 26 апр 21, 15:29
26 апр 21, 15:36    [22314531]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
chpasha
Member

Откуда:
Сообщений: 10838
Эх Стас, закидать бы тебя какашками, как ты сам любишь ;) - 6 использований ((List) mail).get(0)) в одном единственном кусочке кода. Про Introduce variable слыхал ;) ?
26 апр 21, 15:40    [22314535]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 8254
asv79,

>есть сущность в которой одно из полей сделано уникальным
= по русски это айди ID?
Констрейнт?
26 апр 21, 15:42    [22314536]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
Stanislav Bashkyrtsev
Очень много кастов, сложно понимать что тут происходит.. Еще и закомментирована строка. Было бы здорово показывать тут чистый код, без лишнего.

Если бросается NPE, то либо email null, либо mailList. Видимо здесь null возвращается:
          email = eMailingMailRepository.findByEmail((String) ((List) mail).get(0));
Т.е. в concurrentSkipListSet элемент есть, а в базе уже нет. Добавь еще проверку на null.

А в целом - оправдано ли то, что ты дублируешь БД состояние в памяти?
\
тут ситуация иная в коллекции элемент уже есть,а в бд в тот момент времени его еще нет
получается в случае если в бд у нас лежит такой емайл я прохожу по условию - делаю выборку из бд и ничего там не вижу

по дублированию бд - это эксперемент ,так как без коллекции я получал validateConstraintExeption
когда я делал проверку на наличие в базе такого емайл - в тот момент времени его еще не было и в момент записи он уже там есть
короче хз что делать- может количество потоков уменьшить- сейчас их 8
26 апр 21, 15:43    [22314538]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
PetroNotC Sharp
asv79,

>есть сущность в которой одно из полей сделано уникальным
= по русски это айди ID?
Констрейнт?

если бы ID ,это наименование почтового ящика- unique constraint
26 апр 21, 15:44    [22314540]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
chpasha
Эх Стас, закидать бы тебя какашками, как ты сам любишь ;) - 6 использований ((List) mail).get(0)) в одном единственном кусочке кода. Про Introduce variable слыхал ;) ?

зато работает быстро - если ввести переменную -замедляется процесс ,так как все это в цикле ,в котром будет куча мусора из под этих временных объектов - я проверял с переменными и без - на 15 к записей я почти 3 минуты проигрываю .
Это касается лишь списков ,видимо в силу того что при присвоении значения списку идет дорогое копирование- которое замедляет процесс
26 апр 21, 15:48    [22314542]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
Stanislav Bashkyrtsev
Member

Откуда: СПб
Сообщений: 137
Как бы ты не пытался обойти проблему со списками - все равно будет вероятность что два INSERT'а пойдут одновременно. Как правило все делают SELECT, а потом INSERT. Но между этими двумя запросами может еще многое произойти. И всегда есть вероятность ошибки. Обычно все забивают.

В нативном SQL некоторые СУБД поддерживают insert ignore. Вставит только если такой записи нет. Но с ORM'ом прийдется все-таки ожидать иногда ConstraintViolationException. Правда после этого еще желательно Session/EntityManager закрыть или хотя бы очистить..

Сообщение было отредактировано: 26 апр 21, 15:43
26 апр 21, 15:51    [22314545]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
убрал касты для наглядности
  if (list.get(0) instanceof List) {
      for (Object mail : list) {
        if ( mail.get(0).isBlank()) continue;
        EMailingEmail email = new EMailingEmail();
//          var email =eMailingMailRepository.findByEmail(mail.get(0));
        if (concurrentSkipListSet.contains(mail.get(0)) {
          email = eMailingMailRepository.findByEmail( mail.get(0));
        } else {
          email.setEmail((String) (mail.get(0));
          email.setName((String) (mail.get(1));
          email.setUserId(idsMap.get(doc.getString("uid")));

          concurrentSkipListSet.add(mail.get(0));
          eMailingMailRepository.save(email);
        }

        if (mailList.contains(email.getEmail())) continue;
        mailList.add(email.getEmail());
26 апр 21, 15:51    [22314546]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
Stanislav Bashkyrtsev
Как бы ты не пытался обойти проблему со списками - все равно будет вероятность что два INSERT'а пойдут одновременно. Как правило все делают SELECT, а потом INSERT. Но между этими двумя запросами может еще многое произойти. И всегда есть вероятность ошибки. Обычно все забивают.

В нативном SQL некоторые СУБД поддерживают insert ignore. Вставит только если такой записи нет. Но с ORM'ом прийдется все-таки ожидать иногда ConstraintViolationException.

так и что делать - выпиливать эту коллекйию и делать запрос в бд на предмент наличия такой записи- если какой то поток обогнал и записал в это время это значение- второй поток получит эксепшн - и не сможет дальше с этим емайл рабоать- вот этого бы очень не хотелось - хотелость бы отловить ConstraintViolationException но при этом все равно выудить этот емайл и продолжить с ним работу
26 апр 21, 15:57    [22314552]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 9651
Stanislav Bashkyrtsev
Как бы ты не пытался обойти проблему со списками - все равно будет вероятность что два INSERT'а пойдут одновременно. Как правило все делают SELECT, а потом INSERT. Но между этими двумя запросами может еще многое произойти. И всегда есть вероятность ошибки. Обычно все забивают.

В нативном SQL некоторые СУБД поддерживают insert ignore. Вставит только если такой записи нет. Но с ORM'ом прийдется все-таки ожидать иногда ConstraintViolationException. Правда после этого еще желательно Session/EntityManager закрыть или хотя бы очистить..

Я вообще не очень понимаю, чем могут помочь какие-то списки/мапы и прочее....

Если программа многопотоковая ))), то рано или поздно ее могут захотеть запустить на другом компьютере/ноде и так далее. И все списки/мапы и прочее - пойдут лесом и велосипед полностью оквадроколесится

Насчет SELECT так же не понял. SELECT FOR UPDATE - для отсутвующей записи сделать вроде не получится, а делать просто SELECT для проверки и на что-то расчитывать - то как-то ну больно наивно. IMHO единственный нормальный РСУБД вариант INSERT + проверка exception'а.

p.s. Проблему автора не понял. Ну собрал велосипед с квадратными колесами - какой смысл спрашивать, что ездить не удобно?
26 апр 21, 15:58    [22314554]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
Stanislav Bashkyrtsev
Member

Откуда: СПб
Сообщений: 137
asv79
Stanislav Bashkyrtsev
Как бы ты не пытался обойти проблему со списками - все равно будет вероятность что два INSERT'а пойдут одновременно. Как правило все делают SELECT, а потом INSERT. Но между этими двумя запросами может еще многое произойти. И всегда есть вероятность ошибки. Обычно все забивают.

В нативном SQL некоторые СУБД поддерживают insert ignore. Вставит только если такой записи нет. Но с ORM'ом прийдется все-таки ожидать иногда ConstraintViolationException.

так и что делать - выпиливать эту коллекйию и делать запрос в бд на предмент наличия такой записи- если какой то поток обогнал и записал в это время это значение- второй поток получит эксепшн - и не сможет дальше с этим емайл рабоать- вот этого бы очень не хотелось - хотелость бы отловить ConstraintViolationException но при этом все равно выудить этот емайл и продолжить с ним работу
Отлавливай исключение, а затем по этому email'у делай снова SELECT в БД. Т.е. теперь-то он точно уже там есть.

Еще вопрос - я верно понимаю что это какой-то ETL процесс? Нельзя ли сделать разделение задач по потокам такое, чтоб одни и те же пользователи не создавались в разных потоках?
26 апр 21, 16:01    [22314557]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
Stanislav Bashkyrtsev
Отлавливай исключение, а затем по этому email'у делай снова SELECT в БД. Т.е. теперь-то он точно уже там есть.

Еще вопрос - я верно понимаю что это какой-то ETL процесс? Нельзя ли сделать разделение задач по потокам такое, чтоб одни и те же пользователи не создавались в разных потоках?

Спасиб за совет ,сейча попробую ,но это видимо затормозит процесс процентов на 30,что печально очень.

По разделению никак- это миграция списка рассылок- тоесть у одного клиента вася@mai.ru
и у другого может быть такой же ящик в списке
26 апр 21, 16:09    [22314561]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 9651
asv79

...это миграция списка рассылок- тоесть у одного клиента вася@mai.ru
и у другого может быть такой же ящик в списке

Если из реляционной субд в реляционную - то вообще не понятно, нафига нужна Java и многопоток.
Смигрировать сначала справочники, потом смигрировать основную таблицу

IMHO сначало изобретение проблем, потом доблестное их решение
26 апр 21, 16:24    [22314571]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
Leonid Kudryavtsev

Я вообще не очень понимаю, чем могут помочь какие-то списки/мапы и прочее....

Если программа многопотоковая ))), то рано или поздно ее могут захотеть запустить на другом компьютере/ноде и так далее. И все списки/мапы и прочее - пойдут лесом и велосипед полностью оквадроколесится
p.s. Проблему автора не понял. Ну собрал велосипед с квадратными колесами - какой смысл спрашивать, что ездить не удобно?

это программа которая будет запущена все один раз,ее суть перенести данные с монго в постгрес ,после миграции монго вырубается надеюсь навсегда )
26 апр 21, 16:25    [22314574]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 8254
asv79,
Какая миграция если данные не валидные.
26 апр 21, 16:32    [22314579]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 8254
Leonid Kudryavtsev
asv79

...это миграция списка рассылок- тоесть у одного клиента вася@mai.ru
и у другого может быть такой же ящик в списке

Если из реляционной субд в реляционную - то вообще не понятно, нафига нужна Java и многопоток.
Смигрировать сначала справочники, потом смигрировать основную таблицу

IMHO сначало изобретение проблем, потом доблестное их решение
+1
26 апр 21, 16:33    [22314582]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 9651
asv79

есть сущность в которой одно из полей сделано уникальным
есть метод который берет эти сущности и пишет в базу
и все бы хорошо,когда все это в однопоточном режиме- просто делаешь запрос в базу - смотришь есть ли там такое значение если есть то скипаешь и все,либо же кладешь все в какой то сет и проверяешь была ли уже такая запись или нет

Проблема начинается в самом начале, в непонятной постановке

Если в сущности более одного поля и уникальное поле не является PK в исходной системе - то в общем случае, никто не может гарантировать, что одному и тому же e-mail'у будут соответствовать одни и те же данные в других полях

Можно, конечно, разрабатывать программы по методу "первое попавшееся", но потом готовьтесь к ошибка "первое попавшееся не попало" ( C )

Если в исходной системе это PK - то проблемы нет. Сначала мигрируем справочник, потом таблицы ссылающиеся на данный справочник
Если в исходной системе это не PK - то должны быть критерии, как должно быть выполнено объединение в случае противоречивых данных

В крайнем случае, на момент переноса можно данные положить в "плоскую" таблицу , а потом уже из нее с помощью команды SELECT DISTINCT нарезать справочники и смотреть коллизии.

IMHO & AFAIK
26 апр 21, 16:34    [22314584]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 8254
Выключить констрейнты и ключи. Всосать данные. Потом провалидировать.
Так решают без ОРМ и... потоков)))
26 апр 21, 16:34    [22314585]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
PetroNotC Sharp
asv79,
Какая миграция если данные не валидные.

а кого это волнует - там вместо интежера может лежать мапа,а вместо мапы например стринг)
бизнесу же не обьяснить что монго - сама по себе помойка,так туда кидали все лет 5 наверно,сервис менялся ,а патчи никто не писал.
26 апр 21, 16:36    [22314586]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
PetroNotC Sharp
Выключить констрейнты и ключи. Всосать данные. Потом провалидировать.
Так решают без ОРМ и... потоков)))

да это все понятно - кто бы разрешил еше)
26 апр 21, 16:37    [22314589]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 8254
asv79,
Ну потоки же ты придумал.
Если очень нужны то сделай два. Один с начала, другой с конца.
Проблемы?
26 апр 21, 16:40    [22314596]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 8254
asv79
PetroNotC Sharp
Выключить констрейнты и ключи. Всосать данные. Потом провалидировать.
Так решают без ОРМ и... потоков)))

да это все понятно - кто бы разрешил еше)
третий топик где тебе не разрешают.
ОК.
Все равно, постановка хромает.
26 апр 21, 16:42    [22314599]     Ответить | Цитировать Сообщить модератору
 Re: Как избежать проблем )  [new]
asv79
Member

Откуда: Тверь
Сообщений: 3319
PetroNotC Sharp
asv79,
Ну потоки же ты придумал.
Если очень нужны то сделай два. Один с начала, другой с конца.
Проблемы?

а что это даст? дубляж может быть и в начале и в конце и в середине
для понимания это большая монго колеккия где то 4 млн записей ,каждая запись содержит от 1 до 30 к ящиков- ящики должны быть уникальны в постгрес ,но в монго нет .
получается что 8 потоков к примеру начинают бррать эти записи и писать их в бд,и тут хоть с начала хоть с конца ,хоть снизу или сверху - потоки будут писать дубляж- так как сам понимаешь такого количества уникальных ящиков нет в нашей стране,а записи есть)
там процентов 40% наверно дубликаты
26 апр 21, 16:48    [22314605]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2 3 4   вперед  Ctrl      все
Все форумы / Java Ответить