SSIS学习使用十:高级事件行为

这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

翻译参考

本文主要参考翻译自 The Stairway to Integration Services 系列文章的 Advanced Event Behavior – Level 10 of the Stairway to Integration Services,目的在于对 SSIS 有一个全面清晰的认识,所有内容在原文的基础上进行实操,由于版本差异、个人疑问等多种原因,未采用完全翻译的原则,同时也会对文中内容进行适当修改,希望最终可以更有利于学习和了解 SSIS,

感谢支持!


本部分我们关注下事件行为。我们分享两种方法,来管理事件传输的默认行为(冒泡——bubbing),并介绍 父子模式(Parent-Child pattern) 以及其中的 事件行为

关于SSIS任务事件(SSIS Task Events)

打开 "Precedence.dtsx" 包,目前控制流应该如下所示:

上一部分,我们在 "Script Task 4" 和 "序列容器1" 上创建了OnError事件处理程序 —— 称之为"侦听器"。每个 OnError事件处理程序 中我们添加一个 脚本任务 显示包含如下 SSIS变量值 的消息框:

  • System::ErrorCode
  • System::ErrorDescription
  • System::SourceName

在测试之前,让我们验证之前 "Precedence.dtsx" 包构建的一些设置更改。首先,点击 "序列容器1",然后按"F4"键显示属性,确认 ForceExecutionResult 属性仍旧设置为 "Success",然后点击 "Script Task 4",并按"F4"显示属性。修改 MaximumErrorCount 属性为1。

事件和执行状态(Events and Execution Status)

上面设置 "序列容器1" 的 ForceExecutionResult 属性为 "Success",并且没有改为 默认值("None")。这样的意图是演示 "序列容器1" 的 ForceExecutionResult 属性和 "序列容器1" 对错误事件响应之间的相互关系。当 ForceExecutionResult 属性覆盖了 "序列容器1" 的执行状态,它并没有干扰(not interfere)"序列容器1"侦听和响应错误事件的能力。

ForceExecutionResult 设置为 "Success","序列容器1" 可能会忽略错误事件,但是这是不确定的,我们只是证明了这一点。请注意,有忽略事件处理程序的专门的方式,在本篇文章末尾我们将演示该功能。

ForceExecutionResult属性 和 事件处理程序 之间的相互作用为数据集成开发者提供了灵活性。这一点很重要:在不使控制流程失败的情况下,错误可以发生并被侦听到(并响应)。

阻止事件冒泡

缺口处理(事件冒泡的"缺陷") —— 阻止事件冒泡

重要的是要记住,事件冒泡将导致Error事件持续沿执行堆栈向上传输。在我们的示例中,作用域的下一层是 "Precedence.dtsx" 包控制流,它代表 SSIS 包本身。

由于我们尚未更改 "Precedence.dtsx" 包的 MaximumErrorCount 或 ForceExecutionResult 属性,因此当错误冒泡到包容器时,该包将失败。

这可能是,也或者不是预期的行为。

我们面临一个设计决定:

  • A —— 在我们想要捕获错误的任务之上的每个作用域级别上增加容错能力,从而为整个SSIS包增加容错能力(无论是否需要)。

  • B —— 我们可以在"Script Task 4"中中断错误事件(Error event)默认的冒泡行为。

让我们看下选项B。

返回 "Script Task 4" 的OnError事件处理程序,点击顶部的SSIS下拉菜单并点击"变量"(Variables)显示变量窗口。"网格选项"中设置显示"系统变量"。

"System::Propagate" 变量是一个 Boolean 变量,默认为True。"System::Propagate"是事件冒泡的控制变量。

点击 "值"(Value) 列改变默认值 True 为 False。

调试器中执行 "Precedence.dtsx" SSIS包,出现 "Script Task 4" 的提示框时点击 "否"(No)。"Script Task 4" 的 OnError事件处理程序 执行:

随后,"序列容器1" 的 OnError事件处理程序 没有执行,并且 "Script Task 3" 和 "序列容器1" 执行完成。

"Script Task 4" 引发的错误事件被 "Script Task 4" 的OnError事件处理程序听到,但是并没有冒泡到 "序列容器1" 的OnError事件处理程序。

编程控制(Programmatic Control)

我们可以在脚本任务中编程控制事件冒泡。

在 "Script Task 4" 的 OnError事件处理程序 中打开脚本任务编辑器,在 "ReadWriteVariables" 属性中添加 "System::Propagate" 变量。

点击"编辑脚本"按钮打开.Net脚本编辑器,在 Main 函数中添加如下的if语句:

根据 "System::ErrorCode" 变量的值,添加条件逻辑控制"System::Propagate"变量的值。

在执行 "Precedence.dtsx" SSIS包测试之前,修改 "Script Task 4" 的OnError事件处理程序中 "System::Propagate" 变量的默认为原来的True。

通过按"F5",在调试器中运行 “Precedence.dtsx” 包,在 "Script Task 4" 的提示框中点击"否"。可以观察到 "Script Task 4" 的OnError事件处理程序的 "脚本任务" 执行并显示错误事件的详细信息。

后面同样执行完 “Script Task 3” 和 “序列容器1”,错误事件并没有向上冒泡。

事件冒泡已经通过编程进行管理,我们已经在SSIS中实现了动态容错(dynamic fault tolerance)。

自定义错误

我们可以通过更改 "Script Task 4" 引发的 ErrorCode 值来进行测试。

在“控制流”上,打开 "Script Task 4" 编辑器,然后单击“编辑脚本”按钮打开脚本编辑器。在 if 代码块中编辑代码以响应消息框按钮的单击,如下图所示,可以看到 Dts.Events.FireError 方法的智能提示。

注释掉 Dts.TaskResult = (int)ScriptResults.Failure;

添加:

Dts.Events.FireError(-1001, sTaskName, "Script Task 4执行失败!", "", 0);
复制代码

当前代码修改用户点击 "Script Task 4" 询问成功的提示框中 "否"按钮 时的响应,为其生成一个 自定义的错误代码和错误描述(custom error code and error description) —— -1001Script Task 4 failed!

Dts.Events.FireError 方法的参数列表分别是:ErrorCode, SubComponent, Description, HelpFile 和 HelpContext。

调试运行 "Precedence.dtsx" 包。在 "Script Task 4" 的消息提示框中点击"否","Script Task 4" 的OnError事件处理程序中显示消息框变为如下所示:

因为 “Script Task 4” 的 OnError事件处理程序 中 "脚本任务" 的代码仅仅当 "System::ErrorCode"变量值 为 6 时才会设置 "System::Propagate" 为False。所以,当前事件仍会冒泡到"序列容器1"的事件处理程序。

此处演示仅仅在 if 条件语句中隔离单个ErrorCode值。实际中可以根据需要使用其他条件语句,如 C# 中的 Switch 或 VB 中的 Select Case。甚至可以使用SSIS工具箱中的其他选项。

冒泡++

事件冒泡可以扩展到单个SSIS包的范围之外。为了检查事件的这种行为,我们必须花一点时间介绍“父子”SSIS设计模式(Parent-Child SSIS design pattern)

父子SSIS设计模式——Parent-Child SSIS Design Pattern

SSIS执行包任务 用于从 另一个SSIS包 调用 SSIS包。

当一个包调用另一个包时,调用的包(包含"执行包任务"(Execute Package Task)的包)称为父包(parent package),而被"执行包任务"调用的包称为子包(child package)。事实证明,这种描述不仅仅是语义的,也很好地描述了程序包之间的一些有趣行为和交互。

设计父子包

在 “FirstSSIS” 项目解决方案中添加一个新的 SSIS 包。

在解决方案资源管理器中,右击 "SSIS包" 虚拟文件夹,点击 "新建SSIS包"(New SSIS Package)。

一个名为 "Package1.dtsx" 的新包被创建添加到解决方案,右击该包并点击 "重命名",修改新包的名字为"Parent.dtsx"。

打开 "Parent.dtsx" 包,拖拽一个 "执行包任务"(Execute Package Task) 到控制流中。

双击 "执行包任务" 打开执行包任务编辑器。

"执行包任务"(Execute Package Task) 用来执行 另一个SSIS包。另一个SSIS包可以文件形式存储,也可以存储在 SQL Server 中。在"执行包任务编辑器"中需要配置"子包"的运行方式,指定如何引用子包及哪个子包(子包的位置)等。

执行包任务编辑器中添加子包有两种引用方式:项目引用(Project Reference)和外部引用(External Reference)。项目引用可以很方便的引用当前解决方案下的其他包。外部引用用来引用存储在其他位置(文件系统File system 或 SQL Server)的包

因为我们要启动当前解决方案下的另一个SSIS包,因此在"项目引用"下,"PackageNameFromProjectReference" 属性选择 "Precedence.dtsx" 包。

点击确定,关闭“执行包任务编辑器”。当在调试器中执行 "Parent.dtsx" 包时,它将会调用 "Precedence.dtsx" 包。

SSIS的布局调整父子包一起显示

在调试器中执行 SSIS 包之前,我想向您展示一个方便的技巧(a handy trick),以测试参与 父子SSIS设计模式 的SSIS包。

确保 Parent.dtsxPrecedence.dtsx 都打开。左击并抓住 "Precedence.dtsx" 标签,然后向右拖动使其离开原有标签,然后拖动到显示出来的布局线到如下图中的位置,释放鼠标左键。

最后,使父子模式中的两个包显示如下:

执行包及父子间的错误事件处理

点击 "Parent.dtsx" 包的控制流的空白区域,使 "Parent.dtsx" 选中。按"F5"键执行 "Parent.dtsx" 包 —— 它将会调用 "Precedence.dtsx"。

"Script Task 2" 提示框中点 "是","Script Task 4"提示框中点击"否"。确认 "Script Task 4" 的 OnError事件处理程序 和 "序列容器1" 的 事件处理程序 中"脚本任务"生成的 OnError事件处理消息框,确认"Script Task 3"的完成提示。

执行完成后应该如下图所示:

在 "Precedence.dtsx" 中,"Script Task 4"失败 和 "序列容器1"成功。"Parent.dtsx" 中执行包任务失败。这种情况是因为"序列容器1"的ForceExecutionResult属性保留着"Success"设置,一个错误事件冒泡穿过"序列容器1"。

如果没有更多的开发尝试,我们将无法观察到发生的其他情况 —— 比如 "Precedence.dtsx" 包执行失败。下面,向 "Precedence.dtsx" 包添加一个 OnError事件处理程序 进行演示。

复制 "序列容器1" 的 OnError事件处理程序 的 "脚本任务",导航到 "Precedence"包 的 OnError事件处理程序,点击"链接"创建它,然后粘贴"脚本任务"到这。

打开"脚本任务编辑器",然后点击"编辑脚本"按钮。找到 "sSubComponent" 定义的位置。修改为如下代码:

var sSubComponent = "Precedence Package OnError Event Handler";
复制代码

点击 "Precedence.dtsx" 的控制流的空白区域,确保它被选择。按 "F5" 键执行 "Precedence.dtsx" 包,"Script Task 4" 提示框中点击 "No",当 OnError事件处理程序 执行和显示消息框时,观察 "Precedence" 的 OnError事件处理程序,如下:

复制 Precedence 的 OnError事件处理程序 中的 "脚本任务",导航到 "Parent" 包的 OnError事件处理程序,创建 事件处理程序 并粘贴 "脚本任务"。

同样,打开脚本任务编辑器,打开"编辑脚本"按钮,修改 "sSubComponent" 的初始化。

var sSubComponent = "Parent Package OnError Event Handler";
复制代码

点击 "Parent.dtsx" 包控制流的空白区域,确保 "Parent.dtsx" 被选中。按"F5"键执行 "Parent.dtsx" 包。和之前的操作一样,"Script Task 4"提示框中点击"否"。在确认 "Script Task 4"、"序列容器1"、"Precedence"包 的 OnError事件处理程序 的消息框后,"Parent"包的OnError事件处理程序接下来会执行。

这里有几点有趣的事需要指出:

首先,在 父子SSIS设计模式 中,错误事件从 "Precedence.dtsx" SSIS包的 "底部"(Script Task 4),冒泡到"Parent.dtsx" SSIS包的 "顶部"。

Precedence.dtsx包就好像在Parent.dtsx包的“执行包任务”的“作用域内”一样。

第二,最初由 "Script Task 4" 生成的错误事件(Error event)仍然配置为最初的变量值。当 Error事件 冒泡时,ErrorCode,ErrorDescription和SourceName SSIS变量的值保持静态 —— 即使它从子包冒泡到父包。

这种行为适用于所有的SSIS任务事件,不仅仅OnError事件。

最后一件事(DisableEventHandlers属性)

你可能会考虑,在父子SSIS设计模式中,我们需要在子级水平管理事件吗?我们可以仅仅在父级水平管理所有事件吗?

答案是:它取决于是否适合你公司业务的事件管理设计,即使你允许大多数事件冒泡到父包的顶部,也存在有效的用例,可以在子包范围内捕获单个SSIS任务和容器事件。我相信,关键是你现在对配置这些事件的灵活性有了更多的了解。你现在有了可选项,并且所有的选择都很好。

我想讨论的最后一件事是 DisableEventHandlers 属性。

SSIS中的可执行文件 —— 换句话说是 SSIS任务和容器 —— 都有 DisableEventHandlers 属性。

DisableEventHandlers属性由任务或容器范围内的可执行文件继承。其默认值为False。不是所有的属性都是true,这一点很重要。另外 MaximumErrorCount 和 ForceExecutionResult 是不继承的。

点击 "Precedence.dtsx" 控制流,按"F4"显示包属性,修改 DisableEventHandlers 属性为True。

点击 "Parent.dtsx" 包控制流的空白区域,确保"Parent.dtsx"被选中。按"F5"执行"Parent.dtsx"包。同样, "Script Task 4" 提示框中点击"否"按钮。然后,下一个显示的是 "Parent" 的 OnError事件处理程序 的消息框。

为什么?因为 "Precedence.dtsx" SSIS包的事件处理程序现在是禁用的。

同样,你可能希望在 子包事件处理程序内隔离某些事件并停止冒泡。

总结

在本文中,我们关注于事件的行为。并演示了两种方法来更改事件冒泡的默认行为:

  • 使用 DisableEventHandlers 属性禁用事件处理程序;

  • 使用脚本任务在事件处理程序内操纵 System::Propagate SSIS变量的值,取消事件冒泡。

同时,介绍了简单的自定义错误,以及父子模式,检查了父子模式内的事件行为。

注:以上 "Precedence.dtsx" 的包名 "Package1",可通过包属性中的 Name 属性进行修改,使其名字和"Precedence"对应。

猜你喜欢

转载自juejin.im/post/7031341083594342436
今日推荐