2016-12-19 4 views
6

Во время работы над JDBC с Postgres ...Как избежать обновления затор

IsolationLevel = «Читать привержен»

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

ps = con.prepareStatement("UPDATE TableA SET column1=column1-? WHERE column2=? and column3=?;" 
          + "UPDATE TableA SET column1=column1+? WHERE column2=? and column3=?;"); 

Ниже представлен список PostgreSQL журналы для ошибки

2016-12-19 12:25:44 IST STATEMENT: UPDATE TableA SET column1=column1+$1 WHERE column2=$2 and column3=$3 
2016-12-19 12:25:44 IST FATAL: connection to client lost 
2016-12-19 12:25:45 IST ERROR: deadlock detected 
2016-12-19 12:25:45 IST DETAIL: Process 8524 waits for ShareLock on transaction 84942; blocked by process 12520. 
    Process 12520 waits for ShareLock on transaction 84940; blocked by process 20892. 
    Process 20892 waits for ExclusiveLock on tuple (1,5) of relation 25911 of database 24736; blocked by process 8524. 
    Process 8524: UPDATE TableA SET column1=column1-$1 WHERE column2=$2 and column3=$3 
    Process 12520: UPDATE TableA SET column1=column1-$1 WHERE column2=$2 and column3=$3 
    Process 20892: UPDATE TableA SET column1=column1-$1 WHERE column2=$2 and column3=$3 
2016-12-19 12:25:45 IST HINT: See server log for query details. 
2016-12-19 12:25:45 IST CONTEXT: while locking tuple (1,12) in relation "TableA" 
2016-12-19 12:25:45 IST STATEMENT: UPDATE TableA SET column1=column1-$1 WHERE column2=$2 and column3=$3 
2016-12-19 12:25:45 IST LOG: could not send data to client: No connection could be made because the target machine actively refused it. 

В этом многопоточной среде, я Ожидал строки TABLEA, чтобы запертыми за 2 заявления и избегайте тупиковой ситуации.

Я вижу подобный сценарий объясняется в Postgres Docs

Я не мог найти способ, чтобы избежать такого рода тупик. Любая помощь приветствуется. Спасибо

P.S: Autocommit уже установлен FALSE и пробовал использовать подготовленныеСтадии с одним запросом UPDATE.

Что касается несколько запросов ->Multiple queries in one Preparedstatement и this показывают, что Postgres оленьей кожи требует дополнительных настроек.

+1

Обновления не блокируют всю таблицу, только указанную строку. Из документов, которые вы указали: «Лучшая защита от взаимоблокировок, как правило, позволяет избежать их, будучи уверенным, что все приложения, использующие базу данных, получают блокировки на нескольких объектах в последовательном порядке». –

+0

как вы готовите два заявления 'UPDATE'? .. –

+0

Извините, моя ошибка @NickBarnes. Я имел в виду только строки. Мне нужно обновить две строки в этой таблице в многопоточной среде. Как я могу предотвратить тупик в такой ситуации и достичь функциональности? – Vamsidhar

ответ

5

Как @Nick Barnes цитируется в комментарии по ссылке, которую я поделился.

Лучшая защита от тупиков, как правило, чтобы избежать их, будучи , что все приложения, использующие базы данных приобретать замки на нескольких объектов в последовательном порядке.

Специально для взаимоблокировок при обновлении, как указано, порядок обновления приводит к взаимоблокировке.

Пример:

UPDATE Table SET ... WHERE id= 1; 
UPDATE Table SET ... WHERE id= 2; 

и

UPDATE Table SET ... WHERE id= 2; 
UPDATE Table SET ... WHERE id= 1; 

Общее решение состоит в порядке обновления на основе идентификатора. Это и подразумевал последовательный порядок.

Я не понимал этого, пока не борюсь с этим тупиком.

1

По моему опыту, тупик в PostgreSQL, скорее всего, происходит в «реальной жизни», когда вы «пересекаете» обновления в двух длинных транзакциях. (объяснение следует). И довольно сложно даже имитировать тупик на PG. Вот пример - http://postgresql.freeideas.cz/simulate-deadlock-postgresql/ Так классические тупиковые означает:

  • Начинает сделку 1 + сделать обновление на строке 1. Ваша процедура продолжается, но сделка 1 по-прежнему открыта и не совершила.
  • Затем вы начинаете транзакцию 2 + обновляете строку 2. Процедура продолжается, но транзакция 2 все еще открыта и не совершена.
  • Теперь вы пытаетесь обновить строку 2 от транзакции 1, которая заставляет эту операцию ждать.
  • Теперь вы пытаетесь обновить строку 1 от транзакции 2 - в этот момент PG сообщает о взаимоблокировке и завершает эту транзакцию.

Поэтому я рекомендую совершать сделки как можно скорее.

+1

Спасибо за ответ. Но в реальной жизни мы не можем autoCommit. Мне нужно откат в случае, если второе обновление или позднее завершится с ошибкой. – Vamsidhar

+1

Я понимаю это, и я ничего не сказал о «autoCommit». Но если у вас сильно многопоточная среда, и вы оставляете транзакции открытыми в течение относительно длительного времени, то наверняка произойдет тупиковая ситуация. Так работают транзакции. – JosMac