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

Събитието ROLLBACK се задейства в postgresql

Не можете да използвате последователност за това. Имате нужда от една точка на сериализация, през която всички вложките трябва да отидат - в противен случай атрибутът "без празнини" не може да бъде гарантиран. Трябва също така да се уверите, че няма да бъдат изтрити редове от тази таблица.

Сериализацията също така означава, че само една транзакция може да вмъкне редове в тази таблица - всички останали вмъквания трябва да изчакат, докато „предишната“ вмъкване не бъде записана или върната назад.

Един модел как това може да бъде реализирано е да имате таблица, където се съхраняват "поредните" номера. Да предположим, че имаме нужда от това за номера на фактури, които трябва да са без празнини по правни причини.

Така че първо създаваме таблицата, която съдържа "текущата стойност":

create table slow_sequence 
(
  seq_name        varchar(100) not null primary key,
  current_value   integer not null default 0
);

-- create a "sequence" for invoices
insert into slow_sequence values ('invoice');

Сега имаме нужда от функция, която ще генерира следващото число, но която гарантира, че две транзакции не могат да получат следващото число по едно и също време.

create or replace function next_number(p_seq_name text)
  returns integer
as
$$
  update slow_sequence
     set current_value = current_value + 1
  where seq_name = p_seq_name
  returning current_value;
$$
language sql;

Функцията ще увеличи брояча и ще върне увеличената стойност като резултат. Поради update редът за последователността вече е заключен и никоя друга транзакция не може да актуализира тази стойност. Ако транзакцията за повикване е върната назад, актуализацията на брояча на последователностите също. Ако е ангажиран, новата стойност се запазва.

За да сте сигурни, че вской транзакцията използва функцията, трябва да се създаде тригер.

Създайте въпросната таблица:

create table invoice 
(
  invoice_number integer not null primary key, 
  customer_id    integer not null,
  due_date       date not null
);

Сега създайте функцията за задействане и тригера:

create or replace function f_invoice_trigger()
  returns trigger
as
$$
begin
  -- the number is assigned unconditionally so that this can't 
  -- be prevented by supplying a specific number
  new.invoice_number := next_number('invoice');
  return new;
end;
$$
language plpgsql;

create trigger invoice_trigger
  before insert on invoice
  for each row
  execute procedure f_invoice_trigger();

Сега, ако една транзакция направи това:

insert into invoice (customer_id, due_date) 
values (42, date '2015-12-01');

Новият номер се генерира. Втора след това транзакцията трябва да изчака, докато първото вмъкване бъде заето или се върне обратно.

Както казах:това решение не е мащабируемо. Въобще не. Това ще забави значително вашето приложение, ако има много вмъквания в тази таблица. Но не можете да имате и двете:мащабируеми правилно изпълнение на последователност без пропуски.

Също така съм почти сигурен, че има крайни случаи, които не са обхванати от горния код. Така че е много вероятно все още да имате пропуски.




  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 COUNT брой стойности на колони с INNER JOIN

  2. 2 начина за изброяване на всички тригери в PostgreSQL база данни

  3. Неуспешно зареждане на sql модули в клъстера на базата данни по време на инсталацията на PostgreSQL

  4. Добавете колона с времеви клеймо с по подразбиране СЕГА() само за нови редове

  5. Инсталации на postgresql с един екземпляр