Bạn không thể sử dụng một chuỗi cho việc này. Bạn cần một điểm tuần tự hóa duy nhất mà qua đó tất cả phần chèn phải được thực hiện - nếu không, thuộc tính "gapless" không thể được đảm bảo. Bạn cũng cần đảm bảo rằng không có hàng nào bị xóa khỏi bảng đó.
Việc tuần tự hóa cũng có nghĩa là chỉ một giao dịch duy nhất có thể chèn các hàng vào bảng đó - tất cả các phần chèn khác phải đợi cho đến khi phần chèn "trước đó" được cam kết hoặc khôi phục lại.
Một mô hình để có thể thực hiện điều này là có một bảng lưu trữ các số "trình tự". Giả sử chúng ta cần điều này cho các số hóa đơn phải không có khoảng trống vì lý do pháp lý.
Vì vậy, trước tiên chúng tôi tạo bảng để giữ "giá trị hiện tại":
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');
Bây giờ chúng ta cần một hàm sẽ tạo ra số tiếp theo nhưng điều đó đảm bảo rằng không có hai giao dịch nào có thể lấy được số tiếp theo cùng một lúc.
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;
Hàm sẽ tăng bộ đếm và kết quả là trả về giá trị tăng dần. Do update
hàng của chuỗi hiện đã bị khóa và không có giao dịch nào khác có thể cập nhật giá trị đó. Nếu giao dịch gọi được khôi phục lại, thì bản cập nhật cho bộ đếm trình tự cũng vậy. Nếu nó được cam kết, giá trị mới vẫn tồn tại.
Để đảm bảo rằng mọi giao dịch sử dụng chức năng, một trình kích hoạt nên được tạo.
Tạo bảng được đề cập:
create table invoice
(
invoice_number integer not null primary key,
customer_id integer not null,
due_date date not null
);
Bây giờ, hãy tạo hàm kích hoạt và trình kích hoạt:
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();
Bây giờ nếu một giao dịch thực hiện điều này:
insert into invoice (customer_id, due_date)
values (42, date '2015-12-01');
Số mới được tạo. Đ giây sau đó giao dịch cần đợi cho đến khi lần chèn đầu tiên được cam kết hoặc khôi phục.
Như tôi đã nói:giải pháp này không thể mở rộng. Không có gì. Nó sẽ làm chậm ứng dụng của bạn hàng loạt nếu có nhiều nội dung chèn vào bảng đó. Nhưng bạn không thể có cả hai: và có thể mở rộng triển khai đúng một trình tự không có khoảng trống.
Tôi cũng khá chắc chắn rằng có những trường hợp cạnh không được đề cập trong đoạn mã trên. Vì vậy, có nhiều khả năng bạn vẫn có thể gặp khó khăn.