PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

блокиране в postgre при проста заявка за актуализиране

Предполагам, че източникът на проблема е кръгова препратка към външен ключ във вашите таблици.

ТАБЛИЦА vm_action_info
==> ВЪНШЕН КЛЮЧ (last_completed_vm_task_id) РЕФЕРЕНЦИИ vm_task (id)

ТАБЛИЦА vm_task
==> ВЪНШЕН КЛЮЧ (vm_action_info_id) РЕФЕРЕНЦИИ vm_action_info (id)

Транзакцията се състои от две стъпки:

Когато две транзакции ще актуализират един и същи запис в vm_action_info маса в същото време, това ще завърши с блокиране.

Вижте прост тестов случай:

CREATE TABLE vm_task( id integer NOT NULL, version integer NOT NULL DEFAULT 0, vm_action_info_id integer NOT NULL, CONSTRAINT vm_task_pkey PRIMARY KEY (id )) WITH ( OIDS=FALSE ); вмъкване в стойности на vm_task ( 0, 0, 0 ), ( 1, 1, 1 ), ( 2, 2, 2 ); CREATE TABLE vm_action_info( id integer NOT NULL, version integer NOT NULL DEFAULT 0, last_on_demand_task_id bigint, CONSTRAINT vm_action_info_pkey PRIMARY KEY (id ))WITH (OIDS=FALSE);вмъкване в стойности на vm_action_info (0, 0, 0), (1, 1, 1), (2, 2, 2);промяна на таблица vm_taskadd ОГРАНИЧЕНИЕ vm_action_info_fk FOREIGN KEY (vm_action_info_id) REFERENCES vm_action_info (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE;Alter table vm_action_info add CONSTRAINT vm_task_last_on_demand_task_fk FOREIGN KEY (last_on_demand_task_id) REFERENCES vm_task (id) MATCH SIMPLE ON UPDATE NO ACTION ON D; ELETE 


В сесия 1 добавяме запис към vm_task, който препраща към id=2 във vm_action_info

session1=> begin;BEGINsession1=> вмъкване в стойности на vm_task( 100, 0, 2 );INSERT 0 1session1=> 

По същото време в сесия 2 започва друга транзакция:

session2=> begin;BEGINsession2=> вмъкване в стойности на vm_task( 200, 0, 2 );INSERT 0 1session2=> 

След това първата транзакция извършва актуализацията:

session1=> актуализиране на vm_action_info set last_on_demand_task_id=100, version=version+1session1=> където id=2; 

но тази команда увисва и чака заключване.....

тогава втората сесия изпълнява актуализацията ........

session2=> update vm_action_info set last_on_demand_task_id=200, version=version+1 where id=2;BŁĄD:wykryto zakleszczenieSZCZEGÓŁY:Процес 9384 оценява ExclusiveLock на кротка (0,5) relacji 33083 bazy danych 16393; блокиран обект 3808. Процесът 3808 се оценява на ShareLock при транзакция 976; zablokowany przez 9384.PODPOWIEDŹ:Przejrzyj dziennik servera by znaleźć szczegóły zapytania.session2=> 

Открита е безизходица !!!

Това е така, защото и двата INSERT във vm_task поставят споделена ключалка на ред id=2 в таблицата vm_action_info поради препратката към външния ключ. Тогава първата актуализация се опитва да постави заключване за запис на този ред и увисва, защото редът е заключен от друга (втора) транзакция. След това втората актуализация се опитва да заключи същия запис в режим на запис, но той е заключен в споделен режим от първата транзакция. И това води до блокиране.

Мисля, че това може да се избегне, ако поставите заключване на запис на запис във vm_action_info, цялата транзакция трябва да се състои от 5 стъпки:

<предварителен начало; изберете * от vm_action_info, където id=2 за актуализация; вмъкване във vm_task стойности (100, 0, 2); актуализация vm_action_info set last_on_demand_task_id=100, версия=версия+1 където id=2; ангажиране;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да запишете файл с изображение в база данни на Postgres?

  2. Как да разделите низ в PostgreSQL

  3. Изберете къде е първата буква в диапазон ( PostgreSQL )

  4. JPA картографиране на няколко реда с ElementCollection

  5. Изгледите на PostgreSQL създават ли се наново всеки път, когато бъдат запитвани?