连接与会话 oracle

原文链接:http://www.itpub.net/thread-1019290-1-1.html

 

连接与会话
连接并不是会话的同义词,发现这一点时很多人都很诧异。在大多数人眼里,它们都是一样的,但事实上并不一定如此。在一条连接上可以建立0个、一个或多个会话。各个会话是单独而且独立的,即使它们共享同一条数据库物理连接也是如此。一个会话中的提交不会影响该连接上的任何其他会话。实际上,一条连接上的各个会话可以使用不同的用户身份!
在Oracle中,连接只是客户进程和数据库实例之间的一条特殊线路,最常见的就是网络连接。这条连接可能连接到一个专用服务器进程,也可能连接到调度器。如前所述,连接上可以有0个或多个会话,这说明可以有连接而无相应的会话。另外,一个会话可以有连接也可以没有连接。使用高级Oracle Net特性(如连接池)时,客户可以删除一条物理连接,而会话依然保留(但是会话会空闲)。客户在这个会话上执行某个操作时,它会重新建立物理连接。下面更详细地定义这些术语:
         连接(connection):连接是从客户到Oracle实例的一条物理路径。连接可以在网络上建立,或者通过IPC机制建立。通常会在客户进程与一个专用服务器或一个调度器之间建立连接。不过,如果使用Oracle的连接管理器(Connection Manager ,CMAN),还可以在客户和CMAN之间以及CMAN和数据库之间建立连接。CMAN的介绍超出了本书的范围,不过Oracle Net Services Administrator’s Guide(可以从http://otn.oracle.com免费得到)对CMAN有详细的说明。
         会话(session):会话是实例中存在的一个逻辑实体。这就是你的会话状态(session state),也就是表示特定会话的一组内存中的数据结构。提到“数据库连接”时,大多数人首先想到的就是“会话”。你要在服务器中的会话上执行SQL、提交事务和运行存储过程。
可以使用SQL*Plus来看一看实际的连接和会话是什么样子,从中还可以了解到,实际上一条连接有多个会话的情况相当常见。这里使用了AUTOTRACE命令,并发现有两个会话。我们在一条连接上使用一个进程创建了两个会话。以下是其中的第一个会话:
ops$tkyte@ORA10G> select username, sid, serial#, server, paddr, status
2 from v$session
3 where username = USER
4 /
USERNAME SID    SERIAL#    SERVER         PADDR         STATUS
---------             ----      --------          ---------              --------            --------
OPS$TKYTE             153             3196                DEDICATED AE4CF614       ACTIVE
这说明现在有一个会话:这是一个与单一专用服务器连接的会话。以上PADDR列是这个专用服务器进程的地址。下面,只需打开AUTOTRACE来查看SQL*Plus中所执行语句的统计结果:
ops$tkyte@ORA10G> set autotrace on statistics
ops$tkyte@ORA10G> select username, sid, serial#, server, paddr, status
2 from v$session
3 where username = USER
4 /

USERNAME SID    SERIAL#    SERVER         PADDR         STATUS
---------             ----      --------          ---------              --------            --------
OPS$TKYTE             151             1511                DEDICATED AE4CF614       INACTIVE
OPS$TKYTE             153             3196                DEDICATED AE4CF614       ACTIVE

Statistics
----------------------------------------------------------
            0 recursive calls
            0 db block gets
            0 consistent gets
            0 physical reads
            0 redo size
       756 bytes sent via SQL*Net to client
       508 bytes received via SQL*Net from client
            2 SQL*Net roundtrips to/from client
            0 sorts (memory)
            0 sorts (disk)
            2 rows processed
ops$tkyte@ORA10G> set autotrace off
这样一来,我们就有了两个会话,但是这两个会话都使用同一个专用服务器进程,从它们都有同样的PADDR值就能看出这一点。从操作系统也可以得到确认,因为没有创建新的进程,对这两个会话只使用了一个进程(一条连接)。需要注意,其中一个会话(原来的会话)是ACTIVE(活动的)。这是有道理的:它正在运行查询来显示这个信息,所以它当然是活动的。但是那个INACTIVE(不活动的)会话呢?那个会话要做什么?这就是 AUTOTRACE 会话,它的任务是“监视”我们的实际会话,并报告它做了什么。
在SQL*Plus 中启用(打开)AUTOTRACE时,如果我们执行DML操作(INSERT、UPDATE、DELETE、SELECT和MERGE),SQL*Plus会完成以下动作:
(1) 如果还不存在辅助会话[1],它会使用当前连接创建一个新会话。
(2) 要求这个新会话查询V$SESSTAT视图来记住实际会话(即运行DML的会话)的初始统计值。这与第4章中watch_stat.sql脚本完成的功能非常相似。
(3) 在原会话中运行DML操作。
(4) DML语句执行结束后,SQL*Plus会请求另外那个会话(即“监视”会话)再次查询V$SESSTAT,并生成前面所示的报告,显示出原会话(执行DML的会话)的统计结果之差。
如果关闭AUTOTRACE,SQL*Plus会终止这个额外的会话,在V$SESSION中将无法看到这个会话。你可能会问:“SQL*Plus 为什么要这样做,为什么要另建一个额外的会话?”答案很简单。我们在第4章中曾经使用第二个SQL*Plus会话来监视内存和临时空间的使用情况,原因是:如果使用同一个会话来监视内存使用,那执行监视本身也要使用内存。SQL*Plus之所以会另外创建一个会话来执行监视,原因也是一样的。如果在同一个会话中观察统计结果,就会对统计结果造成影响(导致对统计结果的修改)。倘若SQL*Plus使用一个会话来报告所执行的I/O次数,网络上传输了多少字节,以及执行了多少次排序,那么查看这些详细信息的查询本身也会影响统计结果。这些查询可能自己也要排序、执行I/O以及在网络上传输数据等(一般来说都会如此!)。因此,我们需要使用另一个会话来正确地测量。
到目前为止,我们已经看到一条连接可以有一个或两个会话。现在,我们想使用SQL*Plus来查看一条没有任何会话的连接。这很容易。在上例所用的同一个SQL*Plus窗口中,只需键入一个“很容易误解”的命令即DISCONNECT:
ops$tkyte@ORA10G> disconnect
Disconnected from Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 –
Production
With the Partitioning, OLAP and Data Mining options
ops$tkyte@ORA10G>
从技术上讲,这个命令应该叫DESTROY_ALL_SESSIONS更合适,而不是DISCONNECT,因为我们并没有真正物理地断开连接。
注意    在SQL*Plus中要真正地断开连接,应该执行“exit”命令,因为你必须退出才能完全撤销连接。
不过,我们已经关闭了所有会话。如果使用另一个用户账户[2]打开另一个会话,并查询(当然要用你原来的账户名代替OPS$TKYTE)。
sys@ORA10G> select * from v$session where username = 'OPS$TKYTE';
no rows selected
可以看到,这个账户名下没有会话,但是仍有一个进程,相应地有一条物理连接(使用前面的ADDR值)[3]:
sys@ORA10G> select username, program
2 from v$process
3 where addr = hextoraw('AE4CF614');

USERNAME    PROGRAM
---------------       ------------------------------------------------
         tkyte         oracle@localhost.localdomain (TNS V1-V3)
所以,这就有了一条没有相关会话的“连接”。可以使用SQL*Plus的CONNECT命令(这个命令的名字也起得不恰当),在这个现有的进程中创建一个新会话(CONNECT命令叫CREATE_SESSION更合适):
ops$tkyte@ORA10G> connect /
Connected.

ops$tkyte@ORA10G> select username, sid, serial#, server, paddr, status
2 from v$session
3 where username = USER
4 /

USERNAME SID    SERIAL#    SERVER         PADDR         STATUS
---------             ----      --------          ---------              --------            --------
OPS$TKYTE             150             233                   DEDICATED AE4CF614       ACTIVE
可以注意到,PADDR还是一样的,所以我们还是在使用同一条物理连接,但是(可能)有一个不同的SID。我说“可能有”,是因为也许还会分配同样的SID,这取决于在我们注销时是否有别人登录,以及我们原来的SID是否可用。
到此为止,这些测试都是用一条专用服务器连接执行的,所以PADDR正是专用服务器进程的进程地址。如果使用共享服务器会怎么样呢?
注意    要想通过共享服务器连接,你的数据库实例必须先做必要的设置才能启动。有关如何配置共享服务器,这超出了本书的范围,不过这个主题在Oracle Net Services Administrator’s Guide中有详细说明。
那好,下面使用共享服务器登录,并在这个会话中查询:
ops$tkyte@ORA10G> select a.username, a.sid, a.serial#, a.server,
2 a.paddr, a.status, b.program
3 from v$session a left join v$process b
4 on (a.paddr = b.addr)
5 where a.username = 'OPS$TKYTE'
6 /

USERNAME SID    SERIAL# SERVER PADDR         STATUS   PROGRAM
---------             ---       -------          -------          --------            ------           ----------------------
OPS$TKYTE             150            261            SHARED      AE4CF118        ACTIVE                           oracle@localhost(S000)
这个共享服务器连接与一个进程关联,利用PADDR可以联结到V$PROCESS来得出进程名。在这个例子中,可以看到这确实是一个共享服务器,由文本S000标识。
不过,如果使用另一个SQL*Plus窗口来查询这些信息,而保持我们的共享服务器会话空闲,就会看到下面的信息:
sys@ORA10G> select a.username, a.sid, a.serial#, a.server,
2          a.paddr, a.status, b.program
3 from v$session a left join v$process b
4          on (a.paddr = b.addr)
5 where a.username = 'OPS$TKYTE'
6 /

USERNAME SID    SERIAL# SERVER PADDR         STATUS      PROGRAM
---------             ---       -------          ------           --------            --------           -----------------------
OPS$TKYTE             150            261            NONE           AE4CEC1C      INACTIVE                           oracle@localhost(D000)
可以注意到,PADDR不一样了,与连接关联的进程名也改变了。空闲的共享服务器连接现在与一个调度器D000关联。这样一来,我们又有了一种方法来观察指向一个进程的多个会话。可以有数百个(甚至数千个)会话指向一个调度器。
共享服务器连接有一个很有意思的性质:我们使用的共享服务器进程可能随调用而改变。如果只有我一个人在使用这个系统(因为我在执行这些测试),作为OPS$TKYTE反复运行这个查询,会反复生成同样的PADDR:AE4CF118。不过,如果打开多条共享服务器连接,并开始在其他会话中使用这个共享服务器,可能就会注意到使用的共享服务器有变化。
考虑下面的例子。这里要查询我当前的会话信息,显示所用的共享服务器。然后在另一个共享服务器会话中完成一个运行时间很长的操作(也就是说,我要独占这个共享服务器)。再次询问数据库我所用的共享服务器时,很有可能看到一个不同的共享服务器(如果原来的共享服务器已经开始为另一个会话提供服务)。在下面的例子中,粗体显示的代码表示通过共享服务器连接的第二个SQL*Plus 会话:
ops$tkyte@ORA10G> select a.username, a.sid, a.serial#, a.server,
2                a.paddr, a.status, b.program
3       from v$session a left join v$process b
4                on (a.paddr = b.addr)
5       where a.username = 'OPS$TKYTE'
6 /

USERNAME SID    SERIAL# SERVER PADDR         STATUS      PROGRAM
---------             ---       -------          -------          --------            ------             ----------------------
OPS$TKYTE             150            261            SHARED      AE4CF118        ACTIVE                           oracle@localhost(S000)
sys@ORA10G> connect system/manager@shared_server.us.oracle.com
Connected.
system@ORA10G> exec dbms_lock.sleep(20)
ops$tkyte@ORA10G> select a.username, a.sid, a.serial#, a.server,
2                a.paddr, a.status, b.program
3       from v$session a left join v$process b
4                on (a.paddr = b.addr)
5       where a.username = 'OPS$TKYTE'
6 /
USERNAME SID    SERIAL# SERVER PADDR         STATUS      PROGRAM
----------------- -----    -------          ------------   --------------    ------------     -------------------------------
OPS$TKYTE             150            261            SHARED      AE4CF614        ACTIVE                           oracle@localhost(S001)
注意第一次是怎么查询的,我使用了S000作为共享服务器。然后在另一个会话中执行了一个长时间运行的语句,它会独占这个共享服务器,而此时所独占的这个共享服务器恰好是S000。要执行这个长时间运行的操作,这个工作会交给第一个空闲的共享服务器来完成,由于此时没有人要求使用S000共享服务器,所以DBMS_LOCK命令就选择了S000。现在,再次在第一个SQL*Plus会话中查询时,将分配另一个共享服务器进程,因为S000共享服务器正在忙。
有一点很有意思,解析查询(尚未返回任何行)可能由共享服务器S000处理,第一行的获取可能由S001处理,第二行的获取可能由S002处理,而游标的关闭可能由S003负责。也就是说,一条语句可能由多个共享服务器一点一点地处理。
总之,从这一节可以了解到,一条连接(从客户到数据库实例的一条物理路径)上可以建立0个、1个或多个会话。我们看到了这样一个用例,其中使用了SQL*Plus的AUTOTRACE工具。还有许多其他的工具也利用了这一点。例如,Oracle Forms就使用一条连接上的多个会话来实现其调度功能。Oracle 的n层代理认证特性可用于提供从浏览器到数据库的端到端用户鉴别,这个特性也大量使用了有多个会话的单连接概念,但是每个会话中可能会使用一个不同的用户账户。我们已经看到,随着时间的推移,会话可能会使用多个进程,特别是在共享服务器环境中这种情况更常见。另外,如果使用Oracle Net的连接池,会话可能根本不与任何进程关联;连接空闲一段时间后,客户会将其删除,然后再根据检测活动(是否需要连接)透明地重建连接。
简单地说,连接和会话之间有一种多对多的关系。不过,最常见的是专用服务器与单一会话之间的一对一关系,这也是大多数人每天所看到的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值