2012-04-21 22 views
5

Từ tài liệu cho find_or_create:Làm thế nào để tránh điều kiện chủng tộc khi sử dụng phương thức find_or_create của DBIx :: Class :: ResultSet?

Lưu ý: Bởi vì find_or_create() đọc từ cơ sở dữ liệu và sau đó có thể chèn dựa trên kết quả, phương pháp này là đối tượng của một cuộc đua điều kiện . Một quy trình khác có thể tạo bản ghi trong bảng sau khi tìm thấy đã hoàn tất và trước khi tạo đã bắt đầu. Để tránh vấn đề này, hãy sử dụng find_or_create() bên trong một giao dịch.

Có đủ để chỉ sử dụng find_or_create() trong giao dịch trong PostgreSQL không?

Trả lời

6

Không, tài liệu không chính xác. Chỉ sử dụng giao dịch không phải để tránh sự cố này. Nó chỉ đảm bảo rằng toàn bộ giao dịch được khôi phục nếu một ngoại lệ xảy ra - do đó không có trạng thái không nhất quán nào sẽ được duy trì cho cơ sở dữ liệu.

Để tránh vấn đề này, bạn phải khóa bảng - bên trong giao dịch, bởi vì tất cả khóa được phát hành vào cuối giao dịch. Một cái gì đó như:

BEGIN; 
LOCK TABLE mytbl IN SHARE MODE; 

-- do your find_or_create here 

COMMIT; 

Nhưng đó không phải là phép chữa bệnh cho mọi thứ. Nó có thể trở thành một vấn đề hiệu suất, và có thể có deadlocks (các giao dịch đồng thời cùng nhau cố gắng khóa tài nguyên mà tài khoản khác đã khóa). PostgreSQL sẽ phát hiện tình trạng như vậy và hủy tất cả trừ một trong các giao dịch cạnh tranh. Bạn phải chuẩn bị để thử lại thao tác thất bại.

The PostgreSQL manual about locks.

Nếu bạn không có nhiều đồng thời bạn cũng có thể chỉ cần bỏ qua vấn đề. Các khe thời gian là rất nhỏ vì vậy nó chỉ rất hiếm khi thực sự xảy ra. Nếu bạn gặp lỗi vi phạm khóa trùng lặp, điều này sẽ không gây hại, thì bạn cũng đã bao gồm điều này.

+2

Các trang hữu ích khác. Tài liệu: http://www.postgresql.org/docs/current/interactive/mvcc.html PostgreSQL phiên bản 9.1 hoặc mới hơn có thể thực thi tuần tự: http://wiki.postgresql.org/wiki/SSI Các cấp độ cách ly hoặc phiên bản PostgreSQL khác: http : //www.postgresql.org/files/developer/concurrency.pdf – kgrittn

+0

Nhưng cách thích hợp để nắm bắt "lỗi vi phạm khóa trùng lặp" trong DBIC là gì? –

+0

@eugeney: Tôi cho rằng bạn mở một câu hỏi mới cho điều đó, thay vì nhận xét. Bạn luôn có thể liên kết với trang này để tiết kiệm cho mình một số cách gõ. –

0

thi này find_or_create nên ngăn chặn tình trạng chủng tộc, được mô tả trong OP:

eval { 
    $row = $self->model->create({ ... }); 
} 
if([email protected] && [email protected] =~ /duplicate/i) { 
    $row = $self->model->find({ ... }); 
} 

Nó cũng làm giảm find_or_create() đến một truy vấn duy nhất trong trường hợp tốt nhất.

+1

Điều này đảo ngược logic. Nhưng bây giờ bạn có một khe thời gian nhỏ trong đó mục nhập có thể bị xóa - trong trường hợp đó logic sẽ thất bại. Cố gắng để viết đầu tiên là tốn kém hơn so với cố gắng để đọc. Vì vậy, đây chỉ là một cải tiến nếu trùng lặp là rất không phổ biến. Dù bằng cách nào, xung đột cũng rất hiếm, bởi vì khe thời gian rất nhỏ. –

Các vấn đề liên quan