关于oracle database link,使用database link相关的查询语句是否会开启事务呢?我们知道,在数据库中一个简单的select查询语句不会产生事务(select for update会产生事务)。如下测试所示:
我们首先准备测试环境,创建了一个database link: link_nodefine_test,然后我们开始测试
create public database link link_nodefine_test
connect to test identified by "t123$%^"
using '(description =
(address_list =
(address = (protocol = tcp)(host = 10.20.57.24)(port = 1521))
)
(connect_data =
(service_name = gsp.localdomain)
)
)';
下面开始演示一下database link相关的查询是否会开启事务:
sql> show user;
user is "sys"
sql> select userenv('sid') from dual;
userenv('sid')
--------------
939
sql> select xidusn, xidslot, xidsqn
2 from v$transaction, v$session
3 where saddr=ses_addr;
no rows selected
sql> select * from kerry@link_nodefine_test;
id name
---------- --------------------------------
100 kerry
sql> select xidusn, xidslot, xidsqn
2 from v$transaction, v$session
3 where saddr=ses_addr;
xidusn xidslot xidsqn
---------- ---------- ----------
3 14 4122050
sql> alter session close database link link_nodefine_test;
error:
ora-02080: database link is in use
sql> commit; --必须要先commit,才能关闭链接
commit complete.
sql> alter session close database link link_nodefine_test;
session altered.
下面我们创建一个账号test,测试验证database link所指向远程数据库中会话的生存周期,简单测试,你会发现即使一个简单查询(包含database link),会在远程数据库生成一个会话。而且如果不执行alter session close database link xxx关闭对应的database link的话,该会话不会销毁,而是变成inactvie状态。直到其触发了tcp keepalive相关机制后才会被数据库清理。
一旦你执行了database link相关的查询, 那么在远程数据库(10.20.57.24)这个测试服务器的数据库实例中,就会生成对应的会话,而且只有在原数据库执行了“alter session close database link link_nodefine_test”后,对应的会话才会销毁(当然,触发了tcp keepalive相关机制后也会被数据库清理)。有兴趣可以自行测试。
sql> select count(*) from v$session where username='test';
count(*)
----------
1
sql> select count(*) from v$session where username='test';
count(*)
----------
0
sql>
那么问题来了,如果我在会话当中多次使用select * from kerry@link_nodefine_test这类包含database link的语句,是否会在10.20.57.24生成多个会话呢? 还是说这个database link相关的会话会复用呢? 下面我们测试验证一下:
如下所示,同一个会话当中多次使用database link查询,不会在10.20.57.24生成多个会话。 但是如果多个不同会话中都使用database link link_nodefine_test的话,那么就会在(10.20.57.24)中生成多个会话。
那么如果在同一个会话中,使用不同的database link,但是这两个database link使用相同的账号,指向相同的服务器,那么这个是否也共用一个会话呢?答案是不会,而是会生成新的会话。如下测试所示
create public database link link_dediated_test
connect to test identified by "t123$%^"
using '(description =
(address_list =
(address = (protocol = tcp)(host = 10.20.57.24)(port = 1521))
)
(connect_data =
(server = dedicated)
(service_name = gsp.localdomain)
)
)';
关于dblink的查询为什么产生事务的原理分析,参考官方文档transaction processing in a distributed system
two-phase commit mechanism
a database must guarantee that all statements in a transaction, distributed or non-distributed, either commit or roll back as a unit. the effects of an ongoing transaction should be invisible to all other transactions at all nodes; this transparency should be true for transactions that include any type of operation, including queries, updates, or remote procedure calls.
the general mechanisms of transaction control in a non-distributed database are discussed in the oracle database concepts. in a distributed database, the database must coordinate transaction control with the same characteristics over a network and maintain data consistency, even if a network or system failure occurs.
the database two-phase commit mechanism guarantees that all database servers participating in a distributed transaction either all commit or all roll back the statements in the transaction. a two-phase commit mechanism also protects implicit dml operations performed by integrity constraints, remote procedure calls, and triggers.
总结:
oracle数据库中使用dblink的相关查询语句会产生事务, 如果有大量会话使用dblink的话,会在远程数据库产生大量的会话,有时候消耗的连接数量会非常可观。对于dblink在远程数据库的会话,必须先在本地数据库的当前会话commit,然后alter session close database link xxx, 关闭dblink,如果不执行这些操作,只能靠dcd或tcp keeplive机制触发数据库销毁会话。
参考资料:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::p11_question_id:393468893370
https://docs.oracle.com/cd/b28359_01/server.111/b28310/ds_concepts004.htm#admin12120