【发布时间】:2012-01-10 15:50:46
【问题描述】:
所以我们刚刚开始使用存储在 SQL Server 中的 ASP.NET 会话 - 它们非常简洁。但是,由于会话现在通过应用程序池回收持续存在,如果我们部署新代码,这可能会给我们带来问题。有没有办法(除了重新启动 SQL 服务器)强制在此模型中放弃所有会话(或至少应用程序池的所有会话)?
【问题讨论】:
标签: asp.net
所以我们刚刚开始使用存储在 SQL Server 中的 ASP.NET 会话 - 它们非常简洁。但是,由于会话现在通过应用程序池回收持续存在,如果我们部署新代码,这可能会给我们带来问题。有没有办法(除了重新启动 SQL 服务器)强制在此模型中放弃所有会话(或至少应用程序池的所有会话)?
【问题讨论】:
标签: asp.net
将此作为存储过程添加到 ASPState 数据库中:
CREATE PROCEDURE [dbo].[DeleteExpiredSessions]
AS
DECLARE @now datetime
SET @now = GETUTCDATE()
DELETE [ASPState].dbo.ASPStateTempSessions
WHERE Expires < @now
RETURN 0
然后将作业添加到定期运行的 SQL Server 代理(我在午夜运行),在该数据库上执行以下步骤:
dbo.DeleteExpiredSessions
这样可以确保会话到期时,即使创建它们的进程不在身边,它们也会消失。如果您想在重新启动进程时摆脱它们,只需执行:
DELETE [ASPState].dbo.ASPStatsTempSessions
这将删除数据库中的所有会话。
【讨论】:
正如@RobertBeaubien 所写,DeleteExpiredSessions 过程应该处理这个问题。当您创建会话存储数据库时,aspnet_regsql 工具应该已经在数据库中为您创建了该过程。应该有一个 SQL 代理作业每 60 秒调用一次,可能是被意外禁用了。
该过程的 ASP.NET 4.0 版本如下所示:
CREATE PROCEDURE dbo.DeleteExpiredSessions
AS
SET NOCOUNT ON
SET DEADLOCK_PRIORITY LOW
DECLARE @now datetime
SET @now = GETUTCDATE()
CREATE TABLE #tblExpiredSessions
(
SessionID nvarchar(88) NOT NULL PRIMARY KEY
)
INSERT #tblExpiredSessions (SessionID)
SELECT SessionID
FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED)
WHERE Expires < @now
IF @@ROWCOUNT <> 0
BEGIN
DECLARE ExpiredSessionCursor CURSOR LOCAL FORWARD_ONLY READ_ONLY
FOR SELECT SessionID FROM #tblExpiredSessions
DECLARE @SessionID nvarchar(88)
OPEN ExpiredSessionCursor
FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE FROM [ASPState].dbo.ASPStateTempSessions WHERE
SessionID = @SessionID AND Expires < @now
FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID
END
CLOSE ExpiredSessionCursor
DEALLOCATE ExpiredSessionCursor
END
DROP TABLE #tblExpiredSessions
RETURN 0
GO
See here 程序说明。
所涉及的存储过程和 SQL Server 会话状态提供程序背后的机制在 this MSDN article 中进行了说明。
【讨论】:
出于性能原因,我的建议是尽可能远离光标。
我改用合并重写了DeleteExpiredSessions 存储过程:
CREATE PROCEDURE dbo.DeleteExpiredSessions
AS
SET NOCOUNT ON
SET DEADLOCK_PRIORITY LOW
DECLARE @now datetime
SET @now = GETUTCDATE()
CREATE TABLE #tblExpiredSessions
(
SessionID nvarchar(88) NOT NULL PRIMARY KEY
)
INSERT #tblExpiredSessions (SessionID)
SELECT SessionID
FROM dbo.ASPStateTempSessions WITH (NOLOCK)
WHERE Expires < @now
MERGE dbo.ASPStateTempSessions AS [target]
USING #tblExpiredSessions AS [source]
ON ([target].[SessionID] = [source].[SessionID] AND Expires < @now)
WHEN MATCHED
THEN DELETE;
DROP TABLE #tblExpiredSessions
RETURN 0
GO
【讨论】: