正常情況下,在一條語句中如果同時包括數(shù)據(jù)庫鏈和序列,就會出現(xiàn)潛在的問題,而Oracle的官方文檔在這里描述的并不是十分清楚。
以下通過一個例子對同時包括數(shù)據(jù)庫鏈和序列的幾種情況分別進行說明。
首先,大家需要構造一個測試的環(huán)境(注:兩個數(shù)據(jù)庫的GLOBAL_NAMES均為TRUE):
SQL> conn scott/tiger@yangtk
已連接。
SQL> create table test_on_yangtk (id number);
表已創(chuàng)建。
SQL> insert into test_on_yangtk values (1);
已創(chuàng)建 1 行。
SQL> commit;
提交完成。
SQL> create sequence seq_on_yangtk;
序列已創(chuàng)建。
SQL> conn yangtk/yangtk@test4
已連接。
SQL> create table test_on_test4 (id number);
表已創(chuàng)建。
SQL> insert into test_on_test4 values (1);
已創(chuàng)建 1 行。
SQL> commit;
提交完成。
SQL> create sequence seq_on_test4;
序列已創(chuàng)建。
SQL> create database link yangtk connect to scott identified by tiger using 'yangtk';
數(shù)據(jù)庫鏈接已創(chuàng)建。
對于簡單的查詢語句,可以分為以下四種情況。
1.從本地表中讀取數(shù)據(jù),并引用本地序列。
SQL> select seq_on_test4.nextval from test_on_test4;
NEXTVAL
----------
1
2.從本地表中讀取數(shù)據(jù),但訪問遠端序列,這時,需要在序列后面加上數(shù)據(jù)庫鏈名稱。
SQL> select seq_on_yangtk.nextval@yangtk from test_on_test4;
NEXTVAL
----------
1
3.讀取遠端數(shù)據(jù)表中數(shù)據(jù),同時訪問遠端序列。
SQL> select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;
NEXTVAL
----------
2
4.讀取遠端數(shù)據(jù)表中數(shù)據(jù),但是訪問本地序列。
SQL> select seq_on_test4.nextval from test_on_yangtk@yangtk;
NEXTVAL
----------
2
經過測試,此四種情況工作都很正常。
下面,我們來考慮分布式事務——以INSERT INTO SELECT為例。
由于INSERT的表可以是本地表,也可以是遠端表,對于每種情況,對應的子查詢語句都可能包含上面四種情況,下面我們來分別進行具體的分析
一、插入本地表
1.從本地表中讀取數(shù)據(jù),并引用本地序列
SQL> insert into test_on_test4 select seq_on_test4.nextval from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
2.從本地表中讀取數(shù)據(jù),但訪問遠端序列
SQL> insert into test_on_test4 select
seq_on_yangtk.nextval@yangtk from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
3.讀取遠端數(shù)據(jù)表中數(shù)據(jù),同時訪問遠端序列。
SQL> insert into test_on_test4 select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
4.讀取遠端數(shù)據(jù)表中數(shù)據(jù),但是訪問本地序列。
SQL> insert into test_on_test4 select
seq_on_test4.nextval from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
經測試,插入本地表的四種情況,沒有出錯
二、插入遠端表
1.從本地表中讀取數(shù)據(jù),并引用本地序列
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.從本地表中讀取數(shù)據(jù),但訪問遠端序列
SQL> insert into test_on_yangtk@yangtk
select seq_on_yangtk.nextval@yangtk from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
3.讀取遠端數(shù)據(jù)表中數(shù)據(jù),同時訪問遠端序列。
SQL> insert into test_on_yangtk@yangtk
select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
4.讀取遠端數(shù)據(jù)表中數(shù)據(jù),但是訪問本地序列。
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)
根據(jù)測試,第一種情況和第四種情況出現(xiàn)了相同的錯誤。
在和其他所有沒有報錯的情況比較后,可以得到這樣的結論:當插入遠端數(shù)據(jù)表,并使用本地序列時會出現(xiàn)錯誤。
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.
根據(jù)目前的錯誤以及Oracle給出的錯誤原因,初步懷疑對于這種插入遠端數(shù)據(jù)表的分布式事務,實際上是在遠端上執(zhí)行的。因此YANGTK上的scott用戶找不到SEQ_ON_TEST4這個序列。
給YANGTK上的scott用戶增加一個指向TEST4上yangtk用戶的數(shù)據(jù)庫鏈。
SQL> conn scott/tiger@yangtk
已連接。
SQL> create database link test4 connect to
yangtk identified by yangtk using 'test4';
數(shù)據(jù)庫鏈接已創(chuàng)建。
SQL> conn yangtk/yangtk@test4
已連接。
SQL> insert into test_on_yangtk@yangtk select
seq_on_test4.nextval from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
SQL> insert into test_on_yangtk@yangtk select
seq_on_test4.nextval from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
在建立數(shù)據(jù)庫鏈之后,重新執(zhí)行錯誤的語句,這次執(zhí)行沒有出現(xiàn)錯誤。
總結:
假如在一條語句中同時使用數(shù)據(jù)庫鏈和序列,大家需要注意的是:目前可能不僅需要一條到遠端的數(shù)據(jù)庫鏈,還可能同時需要一個從遠端到本地的數(shù)據(jù)庫鏈。
以下通過一個例子對同時包括數(shù)據(jù)庫鏈和序列的幾種情況分別進行說明。
首先,大家需要構造一個測試的環(huán)境(注:兩個數(shù)據(jù)庫的GLOBAL_NAMES均為TRUE):
SQL> conn scott/tiger@yangtk
已連接。
SQL> create table test_on_yangtk (id number);
表已創(chuàng)建。
SQL> insert into test_on_yangtk values (1);
已創(chuàng)建 1 行。
SQL> commit;
提交完成。
SQL> create sequence seq_on_yangtk;
序列已創(chuàng)建。
SQL> conn yangtk/yangtk@test4
已連接。
SQL> create table test_on_test4 (id number);
表已創(chuàng)建。
SQL> insert into test_on_test4 values (1);
已創(chuàng)建 1 行。
SQL> commit;
提交完成。
SQL> create sequence seq_on_test4;
序列已創(chuàng)建。
SQL> create database link yangtk connect to scott identified by tiger using 'yangtk';
數(shù)據(jù)庫鏈接已創(chuàng)建。
對于簡單的查詢語句,可以分為以下四種情況。
1.從本地表中讀取數(shù)據(jù),并引用本地序列。
SQL> select seq_on_test4.nextval from test_on_test4;
NEXTVAL
----------
1
2.從本地表中讀取數(shù)據(jù),但訪問遠端序列,這時,需要在序列后面加上數(shù)據(jù)庫鏈名稱。
SQL> select seq_on_yangtk.nextval@yangtk from test_on_test4;
NEXTVAL
----------
1
3.讀取遠端數(shù)據(jù)表中數(shù)據(jù),同時訪問遠端序列。
SQL> select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;
NEXTVAL
----------
2
4.讀取遠端數(shù)據(jù)表中數(shù)據(jù),但是訪問本地序列。
SQL> select seq_on_test4.nextval from test_on_yangtk@yangtk;
NEXTVAL
----------
2
經過測試,此四種情況工作都很正常。
下面,我們來考慮分布式事務——以INSERT INTO SELECT為例。
由于INSERT的表可以是本地表,也可以是遠端表,對于每種情況,對應的子查詢語句都可能包含上面四種情況,下面我們來分別進行具體的分析
一、插入本地表
1.從本地表中讀取數(shù)據(jù),并引用本地序列
SQL> insert into test_on_test4 select seq_on_test4.nextval from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
2.從本地表中讀取數(shù)據(jù),但訪問遠端序列
SQL> insert into test_on_test4 select
seq_on_yangtk.nextval@yangtk from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
3.讀取遠端數(shù)據(jù)表中數(shù)據(jù),同時訪問遠端序列。
SQL> insert into test_on_test4 select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
4.讀取遠端數(shù)據(jù)表中數(shù)據(jù),但是訪問本地序列。
SQL> insert into test_on_test4 select
seq_on_test4.nextval from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
經測試,插入本地表的四種情況,沒有出錯
二、插入遠端表
1.從本地表中讀取數(shù)據(jù),并引用本地序列
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.從本地表中讀取數(shù)據(jù),但訪問遠端序列
SQL> insert into test_on_yangtk@yangtk
select seq_on_yangtk.nextval@yangtk from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
3.讀取遠端數(shù)據(jù)表中數(shù)據(jù),同時訪問遠端序列。
SQL> insert into test_on_yangtk@yangtk
select seq_on_yangtk.nextval@yangtk from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
4.讀取遠端數(shù)據(jù)表中數(shù)據(jù),但是訪問本地序列。
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)
根據(jù)測試,第一種情況和第四種情況出現(xiàn)了相同的錯誤。
在和其他所有沒有報錯的情況比較后,可以得到這樣的結論:當插入遠端數(shù)據(jù)表,并使用本地序列時會出現(xiàn)錯誤。
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.
根據(jù)目前的錯誤以及Oracle給出的錯誤原因,初步懷疑對于這種插入遠端數(shù)據(jù)表的分布式事務,實際上是在遠端上執(zhí)行的。因此YANGTK上的scott用戶找不到SEQ_ON_TEST4這個序列。
給YANGTK上的scott用戶增加一個指向TEST4上yangtk用戶的數(shù)據(jù)庫鏈。
SQL> conn scott/tiger@yangtk
已連接。
SQL> create database link test4 connect to
yangtk identified by yangtk using 'test4';
數(shù)據(jù)庫鏈接已創(chuàng)建。
SQL> conn yangtk/yangtk@test4
已連接。
SQL> insert into test_on_yangtk@yangtk select
seq_on_test4.nextval from test_on_test4;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
SQL> insert into test_on_yangtk@yangtk select
seq_on_test4.nextval from test_on_yangtk@yangtk;
已創(chuàng)建 1 行。
SQL> rollback;
回退已完成。
在建立數(shù)據(jù)庫鏈之后,重新執(zhí)行錯誤的語句,這次執(zhí)行沒有出現(xiàn)錯誤。
總結:
假如在一條語句中同時使用數(shù)據(jù)庫鏈和序列,大家需要注意的是:目前可能不僅需要一條到遠端的數(shù)據(jù)庫鏈,還可能同時需要一個從遠端到本地的數(shù)據(jù)庫鏈。