JBDC - выполнять SELECT и INSERT атомарно в параллельных потоках - PullRequest
2 голосов
/ 06 марта 2012

Я искал в Интернете простые примеры, но безрезультатно. Мне нужно выполнить операцию select и insert как элементарный элемент в Java, используя JDBC для базы данных Oracle.

Эффективно мне нужно сделать следующее:

  1. Выбор кода от пользователей
  2. Пройдите по всем кодам, пока не найдете тот, который не используется (поскольку пользователи могут быть удалены, в середине диапазона могут быть коды)
  3. Введите нового пользователя с этим доступным кодом

Обычно это простая операция, но, поскольку мое приложение является многопоточным, я не знаю, как это сделать. Поскольку одновременные потоки, работающие в одно и то же время, могут одновременно попытаться вставить и использовать одно и то же значение для кода.

Есть пара обходных путей или хаков, о которых я могу подумать, чтобы выполнить работу, но в целом, как я могу заблокировать таблицу, чтобы сделать эту операцию атомарной? Большая часть того, что я видел, связана с блокировками строк, но поскольку я не обновляюсь, я не понимаю, как это применимо.

Ответы [ 3 ]

1 голос
/ 06 марта 2012

Я бы склонялся к тому, чтобы поместить логику в хранимую процедуру.Используйте «выбрать для обновления», чтобы заблокировать, а затем зафиксировать, чтобы разблокировать.

Вы можете добавить фильтр к оператору вставки и логику повторных попыток на стороне клиента, я думаю:

  • определитьдоступный код (предлагаемый код)
  • выполнить вставку с фильтром, определить количество строк из результата executeUpdate (0 означает, что параллельный поток захватил этот код, повторите попытку)

Вставка будет выглядеть примерно так: 3 - это ваш новый идентификатор, «Джо» - ваш новый пользователь, и предлагается код, который, по вашему мнению, доступен:

INSERT INTO users
  SELECT 3, :proposedCode, 'Joe' 
    FROM dual
    WHERE :proposedCode NOT IN (SELECT code FROM users)
1 голос
/ 06 марта 2012

Как насчет:

insert into usertable (
  id, 
  code, 
  name
) values (
  user_id_sequence.nextval,
  (
      select min(newcode) 
        from usertable, (
           select level newcode 
             from dual 
          connect by level <= (select max(code)+1 from usertable))
       where not exists (select 1 from usertable where code = newcode)
  ),
  'mynewusername'
)

EDIT:

изменено на макс (код) + 1, поэтому, если пробела нет, доступен новый код.

1 голос
/ 06 марта 2012

Это сложная проблема, которую нужно полностью выполнить в SQL.Любое решение будет иметь проблемы с состоянием гонки.Если бы я собирался сделать это полностью в SQL, я бы использовал таблицу удаленного кода.Когда пользователи затем удаляются, вы используете какой-то сервис для добавления их кода в удаленную таблицу.Если таблица удаленных кодов пуста, потоки будут использовать порядковый номер, чтобы получить новый код.Получение кода из удаленного должно быть в блоке synchronized из-за получения, а затем установки природы с несколькими операциями SQL.Я не думаю, что транзакции SQL помогут там.Они могут сохранять согласованность данных, но если два потока используют один и тот же код, то один из двух коммитов вызовет исключение.

Я думаю, что лучший и более быстрый механизм будет иметь отдельное управление потокамиэти удаленные коды.Он может записать его в базу данных, но также сохранить BlockingQueue удаленных кодов для использования другими потоками.Если дыр не должно быть, и вы беспокоитесь о сбое, тогда нужно будет проверить список доступных дыр, выполнив запрос к пользовательской таблице при запуске.Ему не нужно было бы синхронизировать или выполнять какие-либо транзакции SQL, потому что только это будет удаление из таблицы удаленных кодов.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...