5

I have a Powershell script that uses invoke-sqlcmd to apply scripts to a series of development databases. I loop through a list of scripts and compare it to the current release level of the database and then apply the required scripts to get the DB to the release level it needs to be at. Certain databases are reference databases and are in a READ_ONLY state. I connect to those database run an alter DB script setting them to READ_WRITE apply the script then change the back to READ_ONLY. Overall the script works well, the issue is it looks like when PowerShell first opens a connection to the database and applies the first script and then goes to alter the DB back to READ_ONLY the database has objects locked. I've traced it back to the previous connection and a Shared_Transaction_Workspace lock (sys.dm_tran_locks) for what looks to be the previous powershell connection. Why is this connection still open after the invoke-sqlcmd has completed and is there anything I can do about it? Can I force invoke-sqlcmd to use a new connection for each invocation of the cmdlet?

I have tried a messy fix killing the offending connection and then retrying the connection but I think there is something better.

4

3 回答 3

8

我一直这样做,它似乎工作:

[System.Data.SqlClient.SqlConnection]::ClearAllPools()
于 2018-06-28T19:50:40.460 回答
2

好吧,我知道这是一个非常古老的帖子,微软的人告诉他们解决了这个问题(正如大卫布拉班特提到的文章所说),但也许我不是最幸运的人,必须采取一种解决方法才能让它发生.

即使运行 Microsoft SQL Server 2012 (SP1) - 11.0.3128.0 (X64) 我也遇到了同样的问题,经过一些研究后,我找到了一种从 Invoke-Sqlcmd 获取一些参数作为输出的方法,这样我就可以获得当前的会话 ID使用来自 SQL Server 的内置 @@SPID 全局变量的用户进程并与 ADO.NET 建立连接以执行 KILL 子句以关闭打开的连接。

所以让我们来看看在我的案例中应用的解决方法

#Invoke the Invoke-Sqlcmd to execute an script from a file
Invoke-Sqlcmd -Server "[SERVER_NAME]" -Database [DATABASE_NAME] -Username [USER] -Password [PASSWORD] -InputFile [DOT_SQL_FILE_PATH]
#Invoke the Invoke-Sqlcmd to execute a inline SQL statement to get the SessionID as a Powershell variable
$SQLSession = Invoke-Sqlcmd -Server "[SERVER_NAME]" -Database [DATABASE_NAME] -Username [USER] -Password [PASSWORD] -query "select @@spid as SessionID"
# Build query to execute KILL clause
$DbQuery = "KILL " + $SQLSession.SessionID;

# Create SQL connection with ADO.NET
$DbConnection = New-Object System.Data.SqlClient.SqlConnection
$DbConnectionString = "Server = [SERVER_NAME]; Database = [DATABASE_NAME]; User ID=[USER]; Password=[PASSWORD];"
$DbConnection.ConnectionString = $DbConnectionString
$DbConnection.Open()

# Create SQL command for KILL clause
$DbCommand = New-Object System.Data.SQLClient.SQLCommand  
$DbCommand.Connection = $DbConnection 
$DbCommand.CommandText = $DbQuery 

# Execute KILL clause
$DbCommand.ExecuteNonQuery()

# Close connection
$DbConnection.Close()

我希望它有所帮助

于 2015-11-16T22:35:11.877 回答
0

即使我使用的是最新版本的 SSMS(版本 16.5.3 - Build 13.0.16106.4),我仍然遇到这个问题。我还没有弄清楚强制关闭连接的“正确”方法是什么,但我有一个简单的解决方法,可以为我解决问题。如果您只需要从数据库中获取连接,您可以执行以下操作:

  1. 运行正常命令

    Invoke-Sqlcmd -ServerInstance "SOME_SERVER" -Database "SOME_DB" ...
    
  2. 当您准备好从数据库中消除连接时:

    Invoke-Sqlcmd -ServerInstance "SOME_SERVER" -Database "SOME_DB" -Query "use [master];"
    

这会将连接切换到主连接,从而将其从感兴趣的数据库中删除。如果您绝对需要关闭连接,我认为您需要求助于 SqlClient 等。

于 2017-02-14T19:40:52.710 回答