同時使用資料庫鏈和序列時應注意的幾點(轉)

zhouwf0726發表於2019-02-19

在一條語句中如果同時包括資料庫鏈和序列,就會出現潛在的問題,而Oracle的文件在這裡並沒有描述清楚。

下面通過一個例子對同時包括資料庫鏈和序列的幾種情況分別進行說明。


首先,構造一個測試的環境(兩個資料庫的GLOBAL_NAMES均為TRUE):

SQL> conn scott/tiger@yangtk
已連線。
SQL> create table test_on_yangtk (id number);

表已建立。

SQL> insert into test_on_yangtk values (1);

已建立 1 行。

SQL> commit;

提交完成。

SQL> create sequence seq_on_yangtk;

序列已建立。

SQL> conn yangtk/yangtk@test4
已連線。
SQL> create table test_on_test4 (id number);

表已建立。

SQL> insert into test_on_test4 values (1);

已建立 1 行。

SQL> commit;

提交完成。

SQL> create sequence seq_on_test4;

序列已建立。

SQL> create database link yangtk connect to scott identified by tiger using 'yangtk';

資料庫連結已建立。

對於簡單的查詢語句,可以分為四種情況。

1.從本地表中讀取資料,並引用本地序列。

SQL> select seq_on_test4.nextval from test_on_test4;

NEXTVAL
----------
1

2.從本地表中讀取資料,但訪問遠端序列,這時,需要在序列後面加上資料庫鏈名稱。

SQL> select seq_on_yangtk.nextval@yangtk from test_on_test4;

NEXTVAL
----------
1

3.讀取遠端資料表中資料,同時訪問遠端序列。

SQL> select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;

NEXTVAL
----------
2

4.讀取遠端資料表中資料,但是訪問本地序列。

SQL> select seq_on_test4.nextval from test_on_yangtk@yangtk;

NEXTVAL
----------
2

通過測試,這四種情況工作都很正常。

下面,考慮分散式事務——以INSERT INTO SELECT為例。

由於INSERT的表可以是本地表,也可以是遠端表,對於每種情況,對應的子查詢語句都可能包含上面四種情況,下面就一一進行分析。

一、插入本地表

1.從本地表中讀取資料,並引用本地序列

SQL> insert into test_on_test4 select seq_on_test4.nextval from test_on_test4;

已建立 1 行。

SQL> rollback;

回退已完成。

2.從本地表中讀取資料,但訪問遠端序列

SQL> insert into test_on_test4 select seq_on_yangtk.nextval@yangtk from test_on_test4;

已建立 1 行。

SQL> rollback;

回退已完成。

3.讀取遠端資料表中資料,同時訪問遠端序列。

SQL> insert into test_on_test4 select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;

已建立 1 行。

SQL> rollback;

回退已完成。

4.讀取遠端資料表中資料,但是訪問本地序列。

SQL> insert into test_on_test4 select seq_on_test4.nextval from test_on_yangtk@yangtk;

已建立 1 行。

SQL> rollback;

回退已完成。

經測試,插入本地表的四種情況,沒有出錯。

二、插入遠端表

1.從本地表中讀取資料,並引用本地序列

SQL> insert into test_on_yangtk@yangtk select seq_on_test4.nextval from test_on_test4;
insert into test_on_yangtk@yangtk select seq_on_test4.nextval from test_on_test4
*
ERROR 位於第 1 行:
ORA-02289: 序列(號)不存在
ORA-02063: 緊接著line(源於TEST4)
ORA-02063: 緊接著2 lines(源於YANGTK)

2.從本地表中讀取資料,但訪問遠端序列

SQL> insert into test_on_yangtk@yangtk select seq_on_yangtk.nextval@yangtk from test_on_test4;

已建立 1 行。

SQL> rollback;

回退已完成。

3.讀取遠端資料表中資料,同時訪問遠端序列。

SQL> insert into test_on_yangtk@yangtk select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;

已建立 1 行。

SQL> rollback;

回退已完成。

4.讀取遠端資料表中資料,但是訪問本地序列。

SQL> insert into test_on_yangtk@yangtk select seq_on_test4.nextval from test_on_yangtk@yangtk;
insert into test_on_yangtk@yangtk select seq_on_test4.nextval from test_on_yangtk@yangtk
*
ERROR 位於第 1 行:
ORA-02289: 序列(號)不存在
ORA-02063: 緊接著line(源於TEST4)
ORA-02063: 緊接著2 lines(源於YANGTK)

根據測試,第一種情況和第四種情況出現了相同的錯誤。

在和其他所有沒有報錯的情況比較後,可以得到這樣的結論:當插入遠端資料表,並使用本地序列時會出現錯誤。

Oracle的error文件上這樣描述2289錯誤的:

ORA-02289 sequence does not exist
Cause: The specified sequence does not exist, or the user does not have the required privilege to perform this operation.
Action: Make sure the sequence name is correct, and that you have the right to perform the desired operation on this sequence.

根據目前的錯誤以及Oracle給出的錯誤原因,初步懷疑對於這種插入遠端資料表的分散式事務,實際上是在遠端上執行的。因此YANGTK上的scott使用者找不到SEQ_ON_TEST4這個序列。

YANGTK上的scott使用者增加一個指向TEST4上yangtk使用者的資料庫鏈。

SQL> conn scott/tiger@yangtk
已連線。
SQL> create database link test4 connect to yangtk identified by yangtk using 'test4';

資料庫連結已建立。

SQL> conn yangtk/yangtk@test4
已連線。
SQL> insert into test_on_yangtk@yangtk select seq_on_test4.nextval from test_on_test4;

已建立 1 行。

SQL> rollback;

回退已完成。

SQL> insert into test_on_yangtk@yangtk select seq_on_test4.nextval from test_on_yangtk@yangtk;

已建立 1 行。

SQL> rollback;

回退已完成。

建立資料庫鏈之後,重新執行錯誤的語句,這次執行沒有出現錯誤。

如果在一條語句中同時使用資料庫鏈和序列,這時候應當小心,你可能不僅需要一條到遠端的資料庫鏈,還可能需要一個從遠端到本地的資料庫鏈。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/756652/viewspace-242178/,如需轉載,請註明出處,否則將追究法律責任。

相關文章