Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Tôi có thể thực hiện MERGE nguyên tử trong Oracle không?

Đây không phải là vấn đề với MERGE như vậy. Thay vào đó, vấn đề nằm ở ứng dụng của bạn. Hãy xem xét thủ tục được lưu trữ này:

create or replace procedure upsert_t23 
    ( p_id in t23.id%type
      , p_name in t23.name%type )
is
    cursor c is
        select null 
        from t23
        where id = p_id;
    dummy varchar2(1);
begin
    open c;
    fetch c into dummy;
    if c%notfound then
        insert into t23 
            values (p_id, p_name);
    else
        update t23
             set name = p_name
             where id = p_id;
    end if;
 end;

Vì vậy, đây là PL / SQL tương đương với MERGE trên T23. Điều gì xảy ra nếu hai phiên gọi nó đồng thời?

SSN1>  exec upsert_t23(100, 'FOX IN SOCKS')

SSN2>  exec upsert_t23(100, 'MR KNOX')

SSN1 đến đó đầu tiên, không tìm thấy bản ghi nào phù hợp và chèn một bản ghi. SSN2 đến đó thứ hai nhưng trước khi SSN1 cam kết, không tìm thấy bản ghi nào, chèn bản ghi và treo vì SSN1 có một khóa trên nút chỉ mục duy nhất cho 100. Khi SSN1 thực hiện hành vi SSN2 sẽ dẫn đến vi phạm DUP_VAL_ON_INDEX.

Câu lệnh MERGE hoạt động theo cùng một cách. Cả hai phiên sẽ kiểm tra on (t23.id = 100) , không tìm thấy nó và đi xuống nhánh INSERT. Phiên đầu tiên sẽ thành công và phiên thứ hai sẽ vượt qua ORA-00001.

Một cách để xử lý điều này là giới thiệu khóa bi quan. Khi bắt đầu quy trình UPSERT_T23, chúng tôi khóa bảng:

...
lock table t23 in row shared mode nowait;
open c;
...

Bây giờ, SSN1 đến, lấy khóa và tiến hành như trước. Khi SSN2 đến, nó không thể lấy được khóa, vì vậy nó bị lỗi ngay lập tức. Điều này gây khó chịu cho người dùng thứ hai nhưng ít nhất họ không bị treo, thêm vào đó họ biết ai đó đang làm việc trên cùng một bản ghi.

Không có cú pháp nào cho INSERT tương đương với SELECT ... FOR UPDATE, vì không có gì để chọn. Và vì vậy cũng không có cú pháp nào như vậy cho MERGE. Những gì bạn cần làm là đưa câu lệnh LOCK TABLE vào đơn vị chương trình đưa ra MERGE. Điều này có khả thi với bạn hay không tùy thuộc vào khuôn khổ bạn đang sử dụng.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để thêm truy vấn thời gian trong Oracle?

  2. Kết nối với Oracle mà không cần tnsname.ora

  3. Bật SSL hoặc TLS trong Oracle Apps R12

  4. Truy xuất ROWID được chèn lần cuối trong PHP / OCI

  5. Có biểu thức CASE như vậy trong JPQL không?