我创建了一个 SQLCLR 用户定义函数,它调用 native C++ DLL。
native C++ DLL 是我的,如果我想对其进行更改,我需要停止 sqlservr 进程来复制新的。在生产中这是 Not Acceptable 。
即使我删除使用该 DLL 的程序集,该文件仍在使用中。
如何覆盖 native DLL?
编辑
DLL方法声明:
[DllImport("Library64.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr GetTiming();
MS 似乎在第一次调用它时加载库,并且似乎在进程终止时卸载......:)
最佳答案
听起来“引用”是由应用程序域持有的。您可以尝试卸载应用程序域,这应该可以清除该问题(最好的猜测,因为我无法测试这一点)。您可以通过对数据库进行任何安全更改来做到这一点。作品如下:
ALTER DATABASE {db_name} SET TRUSTWORTHY ON (or OFF if already ON);
GO
ALTER DATABASE {db_name} SET TRUSTWORTHY OFF (or ON if already OFF);
GO
请记住,这将卸载该特定数据库中的所有 AppDomain。这通常不是问题,因为人们很少在单个数据库中拥有多个应用程序域(这需要程序集由不同的用户拥有,并且大多数人只使用 dbo
)。
要查看存在哪些应用程序域以及加载了哪些程序集,请运行以下命令:
SELECT DB_NAME(dca.[db_id]) AS [DatabaseName], dca.*, '---' AS [---], dcla.*
FROM sys.dm_clr_appdomains dca
INNER JOIN sys.dm_clr_loaded_assemblies dcla
ON dca.appdomain_address = dcla.appdomain_address
WHERE dca.[db_id] <> 32767;
如果该查询没有返回任何内容,并且您仍然无法替换该外部 DLL,请尝试以下操作(这似乎有点多,但在尝试其他操作之前我们需要知道它是否有效):
sp_configure 'clr enabled', 0;
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
RECONFIGURE;
另外两个可以尝试的选项是:
创建一个可通过 DLLImport 调用的包装 DLL。它会调用你的 Library64.dll
最后的手段是通过另一个非托管调用强制删除非托管 DLL。您没有使用
LoadLibrary()
创建 DLL ,但您应该能够使用GetModuleHandleExA()
获得对它的引用然后在调用FreeLibrary()
时使用该句柄。以下博客文章对此进行了描述:PInvoke Library Load/Unload Behavior – Freeing Unmanaged Libraries 。 似乎这是唯一成功的方法。请参阅@John's answer具体代码。
关于sql-server - 如何从 SQL Server 进程卸载 native DLL(使用 [DllImport()] 属性加载)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32290350/