Oracle SQL会话的生命周期是什么



我在Oracle SQL server中发现了全局临时表的概念。根据关于全局临时表的教程:

全局临时表中的数据是私有的,因此由会话插入的只能由该会话访问。

我相信这可以允许以下场景:客户端启动一个存储过程两次,每次都事先用sp要处理的数据填充一个全局临时表。这两种计算不会相互干扰,因为每种计算都只看到自己的数据,而不是像常规表那样共享数据。

然而,这完全取决于会话的组成,以及会话的开始和结束时间。

根据Oracle数据库概念词汇表:

会话:数据库实例内存中的逻辑实体,表示当前用户登录数据库的状态。单个连接上可以建立0、1或更多会话。

连接:客户端进程和Oracle数据库实例之间的通信路径。

这并没有消除我所有的困惑,所以这是我的具体问题:

我的应用程序在其整个生命周期中维护与Oracle SQL服务器的单一连接。它在同一连接上连续执行多个SQL命令/查询,这些查询中的每一个都是自己的会话吗?它们会共享一个会话吗?

考虑一下这个伪代码:

Command c1 = new Command("insert into TMP_TABLE (FOO) values ('TEST')");
Command c2 = new Command("select FOO from TMP_TABLE");
c1.Execute();
foreach (var value in c2.Query().Select("FOO"))
{
print(value);
}

我已经在我的应用程序中运行了上述操作,正如预期的那样,命令c2返回了零个结果。我认为这意味着每个查询都构成了自己的会话,这就是我想要的。但我能相信吗?

Oracle SQL会话的生命周期是什么

会话是一个逻辑实体,从应用程序代码连接到数据库到断开连接一直存在。

会话独立于支持它们的物理(基于资源的)实体,例如连接、服务器进程、网络连接等。

在最简单(也是最常见的imo)配置(即"专用服务器")中,逻辑会话与物理连接和服务器进程之间存在1-1的关系。在支持大量用户的更高级配置中,物理资源(连接、进程、网络资源)可以由多个会话共享/在多个会话之间多路复用。

我已经在应用程序中运行了上述操作,不出所料,命令c2返回了零个结果。我认为这意味着每个查询都构成了自己的会话

除非您的应用程序代码在调用之间断开连接或关闭/释放连接,否则几乎可以肯定的是,情况并非如此。

全局临时表可以通过两个选项创建:ON COMMIT DELETE ROWSON COMMIT PRESERVE ROWS

第一个将导致在commitrollback上移除所有GTT数据。第二个将导致所有GTT数据在整个会话中保持不变。

如果您没有使用ON COMMIT DELETE ROWS,那么您应该而不是假设GTT在给定调用开始时为空。若您在过程开始时要求GTT为空,则必须在过程开始(或结束)时DELETE FROM您的GTT(或TRUNCATEit)。

请注意,即使有这种限制(即,必须自己在会话中清空GTT),全局临时表仍然很有用,因为它们仍然可以保护一个会话看不到另一个会话的数据。与常规表相比,它们编写的重做更少,尤其是在12.1及更高版本中。事实上,从Oracle12.1开始,它们根本不需要写任何重做,这使得它们在只读和备用数据库中非常有用。

除此之外

我已经在我的应用程序中运行了上述操作,正如预期的那样,命令c2返回了零结果

要做到这一点,您的GTT必须使用ON COMMIT DELETE ROWS创建,并且您的应用程序代码启用了某种"自动提交"功能,在每次Command.Execute()之后自动提交。否则你会误解/误报你的测试结果。

我不知道您的应用程序是否在调用之间维护Oracle会话,但无论哪种方式,您都需要注意假设全局临时表(GTT)在第二次调用时为空。因为如果它每次都得到一个"新"会话,那么这可能真正意味着你从连接池中获得了一个空闲会话。该会话的前一个用户(可能是您)可能已经填充了该会话的GTT。我发现在使用OracleApplicationExpress(APEX)时就是这样,它是一个基于HTTP的应用程序框架。

您需要调用一个使用GTT的Oracle存储过程,然后截断(清空)它(和/或在使用它之前截断它),以确保每次都能得到一个干净的记录。

Oracle清除COMMIT/ROLLBACK操作中的TEMPORARYTABLE内容。

因此,如果Command类在命令之后发出COMMIT,它也会清除temp表中的数据,而next命令看不到任何内容。

问题:"我的应用程序在其整个生命周期中都保持着与Oracle SQL服务器的单一连接。它在同一连接上连续执行多个SQL命令/查询,这些查询中的每一个都是自己的会话吗,它们会共享一个会话吗,还是答案不简单?">

如果这正是您对它的描述,那么每个查询都在其自己的CURSOR而不是会话中运行。如果您在会话上运行跟踪并查看原始跟踪文件,您将看到PARSING IN CURSOR等部分,在这些部分中,SQL将被解析并检查语法和权限,然后是EXEC,在服务器上执行,在FETCH中,结果集将被提取到客户端,而在CLOSE中,光标将被关闭。如果您的查询已经完成,那么您的光标将隐式关闭;但是,使用PL/SQL和游标编程,可以显式控制/打开/关闭游标。隐式游标可以重用,因为Oracle在内部为每个游标分配了一个数字。即使你打开一个SQL*Plus连接并运行一个查询,oracle也会为它分配一个游标

示例:

PARSING IN CURSOR #18446744071393882224 len=51 dep=2 uid=63403 oct=3 lid=63403 tim=29425147118918 hv=682153908 ad='3e6edfd80' sqlid='344kggsnajpxn'
SELECT "BDD_EXTERNALBATCH_ID_SEQ".NEXTVAL FROM DUAL
END OF STMT
EXEC #18446744071393882224:c=73,e=73,p=0,cr=0,cu=0,mis=0,r=0,dep=2,og=1,plh=1849910378,tim=29425147118915
FETCH #18446744071393882224:c=9161,e=9402,p=0,cr=2,cu=3,mis=0,r=1,dep=2,og=1,plh=1849910378,tim=29425147128989
CLOSE #18446744071393882224:c=9,e=8,dep=2,type=3,tim=29425147129472

现在,例如,如果您通过Weblogic实现了连接池,那么您就打开了连接池中定义的许多SESSIONS,每个查询都通过Weblogic处理到相应的会话。有时Weblogic会扩大或缩小池(在配置参数内),当池扩大时,您将创建更多会话。

如果您选择这样做,您也可以在每个查询自己的会话中运行每个查询,但这是一个非常糟糕的想法,并且由于性能原因不可扩展。最好在会话范围内或通过存储过程和包在服务器上运行尽可能多的查询和DML。

关于GTT(全局临时表),它们在会话中使用,并在会话关闭时解除分配。除了GTT的明显用途外,我们还使用它们将某些类别的用户转移到不同的临时段(通过巧妙地使用视图和触发器),因为在繁忙的系统中,临时段可能存在非常高的竞争。

最新更新