Là một chức năng bị bỏ (hoặc thay đổi) vẫn có sẵn trong các giao dịch đã mở?


7

tôi đã tìm thấy

nhưng không có câu trả lời và không hoàn toàn giống với câu hỏi của tôi (mặc dù rất giống nhau).


Hãy nói tôi làm như sau:

  1. Tạo một chức năng myfunc()
  2. Bắt đầu giao dịch từ khách hàng A
  3. Bắt đầu giao dịch từ khách hàng B
  4. Trong giao dịch B, sử dụng "tạo hoặc thay thế chức năng" để sửa đổi định nghĩa về myfunc()
  5. Cam kết giao dịch B
  6. Gọi myfunc()từ giao dịch A

Điều gì xảy ra ở bước 6? Tôi có gọi hàm ban đầu như được định nghĩa trong bước 1 không? Hoặc hình thức sửa đổi từ bước 4 (cam kết ở bước 5)?


Và nếu chức năng bị bỏ ở bước 4 thay vì bị sửa đổi, bước 6 sẽ thất bại hay thành công? (Đây có thể là cùng một câu hỏi nhưng sửa đổi có thể hoạt động khác nhau.)


Tài liệu về điều này ở đâu?

Câu trả lời:


4

Điều gì xảy ra ở bước 6?

Giao dịch A thấy định nghĩa cập nhật của chức năng myfunc()ngay lập tức. (Nhưng hãy xem tác dụng của bộ đệm bên dưới.)

Và nếu chức năng bị bỏ ở bước 4 thay vì bị sửa đổi, bước 6 sẽ thất bại hay thành công?

Nó sẽ thất bại. (Nhưng hãy xem tác dụng của bộ đệm bên dưới.)

Các lệnh DDL của Postgres hoàn toàn giao dịch. Mặc dù giao dịch B không cam kết, cả hai giao dịch sẽ tiếp tục thấy các phiên bản khác nhau của chức năng. Nhưng các giao dịch đồng thời không thấy các thay đổi cam kết trong danh mục hệ thống. Sẽ có vẻ rõ ràng ở mức cô lập mặc định READ COMMITTED. Nhưng bạn thậm chí không thể ngăn chặn điều này với các mức cô lập REPEATABLE READhoặc SERIALIZABLE.

Nếu bạn nên gọi hàm trong giao dịch A trước khi giao dịch B thực hiện thay đổi, bộ đệm cục bộ có thể can thiệp. Trong các thử nghiệm của tôi, một cuộc gọi nữa đã hoạt động với chức năng được lưu trong bộ nhớ cache (cũ) trước khi cuộc gọi tiếp theo nhận thức được sự thay đổi và được trả lời tương ứng.

Tôi không tìm thấy tài liệu về cách bộ đệm danh mục hệ thống hoạt động chính xác cho điều này (vẫn có thể tồn tại ở đâu đó). Tôi không tin rằng bit cuối cùng (thêm một cuộc gọi được trả lời từ bộ đệm) là hành vi tốt nhất có thể.


BTW, các bước của bạn 3. - 5. có thể giảm xuống chỉ còn 4., không có sự khác biệt. Các trình bao bọc giao dịch rõ ràng hoặc ẩn hoạt động như nhau:

3. Bắt đầu giao dịch từ khách hàng B
4. Trong giao dịch B, sử dụng "tạo hoặc thay thế chức năng" để sửa đổi định nghĩa của myfunc ()
5. Cam kết giao dịch B


Tuyệt quá! Vì vậy, để kiểm tra sự hiểu biết của tôi, nếu bước 5 bị bỏ qua, thì liệu bước 4 đã bỏ hoặc sửa đổi chức năng, bước 6 sẽ thành công và sẽ chạy phiên bản gốc?
tự đại diện

1
@Wildcard: Nếu bạn có bước 3 ( BEGIN;), nhưng không bước 5 ( COMMIT;) thay đổi của bạn, cho dù DROPhoặc REPLACElà không bao giờ nhìn thấy bất kỳ giao dịch khác ngoài giao dịch B. Bạn sẽ phải COMMIThoặc ROLLBACKsớm hay muộn, mặc dù. Tốt hơn sớm hơn, giao dịch nhàn rỗi không nên diễn ra quá lâu, nó sẽ chặn hoạt động kinh doanh khác ...
Erwin Brandstetter

Cảm ơn; điểm về không bao giờ có thể nhìn thấy đối với bất kỳ giao dịch nào khác có vẻ rõ ràng nhưng ngoại lệ đối với TRUNCATE khiến tôi không chắc chắn.
tự đại diện

6

Câu hỏi thú vị.

Từ một thử nghiệm nhỏ, có vẻ như các sửa đổi và xóa chức năng là giao dịch. Có nghĩa là - trong bất kỳ mức cô lập nào - khi giao dịch 2 sửa đổi hoặc xóa chức năng, giao dịch 1 không biết đến nó và vẫn sử dụng phiên bản cũ của chức năng.

Mọi thay đổi đối với chức năng chỉ hiển thị sau khi giao dịch được thực hiện và chỉ đối với các giao dịch bắt đầu sau cam kết đó. Mức cô lập là không liên quan, vì hàm được kiểm tra không đọc bất kỳ dữ liệu nào từ bất kỳ bảng nào.

-- Create Function
x=# create or replace function f() returns integer as
$$ select 1 ; $$ immutable language sql ;
CREATE FUNCTION

-- TRAN 1
x=# begin ;
BEGIN
x=# select * from f() ;
 f 
---
 1
(1 row)
                    -- TRAN 2
                    x=# begin ;
                    BEGIN
                    x=# drop function f () ;
                    DROP FUNCTION
                    x=# commit ;
                    COMMIT
-- TRAN 1
x=# select * from f() ;
 f 
---
 1
(1 row)
x=# commit ;
COMMIT

-- After COMMIT
x=# select * from f() ;
ERROR:  function f() does not exist
LINE 1: select * from f() ;
                      ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
x=# 

Trong một kịch bản hơi khác, nếu cả hai giao dịch đều cố gắng sửa đổi chức năng, thì chỉ có một giao dịch thành công và giao dịch kia bị chặn và sau đó thất bại nếu lần đầu tiên thực hiện.


2
Tôi không đồng ý với kết luận này. Nếu bạn xóa cái đầu tiên select * from f()khỏi TRAN1 trong chế độ đã đọc, thì cái thứ hai select * from f()sẽ thất bại. Thử nghiệm trên dường như chứng minh hiệu quả của bộ đệm tra cứu cục bộ đối với TRAN1 hơn là những gì bạn kết luận trong câu trả lời.
Daniel Vérité

@ DanielVérité Tôi đã thử nhiều thứ, bao gồm những gì bạn nói, trong tất cả các cấp độ cô lập. Nó không thành vấn đề. Bạn có không đồng ý với phần đầu tiên (hoặc phần thứ hai về cả hai sửa đổi chức năng không?)
ypercubeᵀᴹ

@ DanielVérité bạn đã kiểm tra với một chức năng khác (có liên quan đến việc đọc từ bảng) chưa?
ypercubeᵀᴹ

Chính xác là bài kiểm tra giống như bạn, đã sao chép từ câu trả lời, PG 10, tất cả các mặc định, ngoại trừ không gọi select * from f() TRAN1 trước khi bỏ chức năng trong giao dịch khác.
Daniel Vérité

Kỳ dị. Tôi hiểu những gì bạn nói, chỉ khi tôi sử dụng chức năng đọc dữ liệu (Postgres 9.6) tôi cũng sẽ thực hiện thêm nhiều bài kiểm tra trong 10 và chỉnh sửa câu trả lời.
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.