在MSSQL中使用托管代码
- 综述
MSSQL是个非托管的应用程序,但是开发人员可以用托管代码创建数据库存储过程、触发器或者函数。
这样开发人员就可以利用其他语言来编写数据库存储过程、触发器或者函数,不仅可以使用FCL或其他程序集中的类型,还可以享受.net framerwork中强大类库的功能。
当首次请求一个用托管代码写的存储过程时, MSSQL会加载CLR,存储过程会在独立的应用程序域运行,这样不会对数据库本身产生影响。托管代码会被JIT编译成本地代码执行,而不是解释执行,这保证了托管代码的执行效率。
- 编写托管代码
为了使用托管代码创建数据库存储过程、触发器或者函数,只需要对托管代码中具体方法使用Microsoft.SqlServer.Server命名空间下的特性:[SqlProcedure]、[SqlFunction]或者[SqlTrigger]。当然方法的参数和返回值相应会有一定的限制。
比如写一个随机散列算法的方法,声明成MSSQL的存储过程:
GetHashText方法
1 namespace Wuhong.ClrSp
2 {
3 public class StoredProcedures
4 {
5 [Microsoft.SqlServer.Server.SqlProcedure]
6 public static void GetHashText(string plainText, out string encryptedText, ref int hashProvider, ref string saltText)
7 {
8 //方法体略……
9 }
10 }
11 }
至此,可以利用托管代码完成一切数据库脚本所无法完成的功能。
特别的,托管代码中也可以访问当前的数据库,但与普通方法访问数据库有两处不同:
一是连接字符串要使用上下文链接(Context
Connection),"context connection=true"。这表示代码中的数据库上下文跟托管代码调用方的数据库上下文一致。
二是将结果集、消息或命令执行结果发送回客户端时需要通过数据库上下文专门的管道对象SqlContext.Pipe来发送。
- 开启CLR集成
默认情况下, CLR集成功能在MSSQL中处于禁用状态。若要使用 SQL CLR 项目项,必须启用 CLR 集成。
sp_configure
1 sp_configure 'clr enabled',1
2 GO
3 RECONFIGURE
4 GO
- 创建程序集
生成托管代码程序集后,需要在MSSQL中创建相应的托管应用程序模块,将其作为MSSQL实例中的对象。通过引用此模块,可在数据库中创建CLR函数、存储过程、触发器。
创建ASSEMBLY
1 CREATE ASSEMBLY [Wuhong.ClrSp]
2 FROM 'F:\website\Wuhong.ClrSp.dll'
3 WITH PERMISSION_SET = SAFE;
WITH PERMISSION_SET指定MSSQL向程序集授予的一组代码访问权限。SAFE是默认值。
SAFE 是最具限制性的权限集。由具有 SAFE 权限的程序集所执行的代码将无法访问外部系统资源,例如文件、网络、环境变量或注册表。
EXTERNAL_ACCESS 使程序集可以访问某些外部系统资源,例如文件、网络、环境变量以及注册表。
UNSAFE 可使程序集不受限制地访问资源,无论是MSSQL实例内部还是外部的资源都可以访问。从 UNSAFE 程序集内运行的代码可调用未托管代码。
UNSAFE 可使程序集不受限制地访问资源,无论是MSSQL实例内部还是外部的资源都可以访问。从 UNSAFE 程序集内运行的代码可调用未托管代码。
创建托管应用程序集的操作也可以在MSSQL
Management Studio中手工完成。
- 创建存储过程
下面是根据创建的托管模块来创建存储过程。
创建PROCEDURE
1 CREATE PROCEDURE [dbo].[GetHashText]
2 @plainText [nvarchar](4000),
3 @encryptedText [nvarchar](4000) OUTPUT,
4 @hashProvider [int] OUTPUT,
5 @saltText [nvarchar](4000) OUTPUT
6 WITH EXECUTE AS CALLER
7 AS
8 EXTERNAL NAME [Wuhong.ClrSp].[StoredProcedures].[GetHashText]
9 GO
WITH EXECUTE AS指定执行模块的上下文,可以控制 数据库引擎使用哪一个用户帐户来验证对模块引用的对象的权限。CALLER是默认值。
CALLER指定模块内的语句在模块调用方的上下文中执行。这表示执行模块的用户不仅必须对模块本身拥有适当的权限,还要对模块引用的任何数据库对象拥有适当权限。
OWNER指定模块内的语句在模块的当前所有者上下文中执行。
SELF指定模块内的语句在创建或更改模块的用户的上下文中执行。
'user_name'指定模块内的语句在user_name指定的用户的上下文中执行。