SSRS代码共享变量和同时报告执行

时间:2010-01-14 21:02:47

标签: sql-server vb.net optimization reporting-services thread-safety

我们有一些SSRS报告在两个报告执行得非常接近时失败。

我发现如果SSRS报告的两个实例同时运行,那么在类级别(不在函数内部)声明的任何Code变量都可能发生冲突。我怀疑这可能是我们报告失败的原因,我正在努力解决这个问题。

我们使用SSRS的代码部分的原因是自定义组和页眉计算等。代码从TextBoxes中的表达式调用,并返回当前标签应该是什么。代码需要维护状态以记住最后一个标头值是什么,以便在未知时返回它,或者存储新的标头值以供重用。

注意:这是我的变量碰撞问题的资源:

MSDN SSRS Forum

  

因为这使用静态变量,如果两个人以完全相同的方式运行报表   一刻,有一个很小的机会可以粉碎对方的变量状态(在SQL 2000中,   这可能偶尔会发生,因为有两个用户在同一个报告中进行分页   同时,不仅仅是由于完全同时执行)。如果你需要100%   一定要避免这种情况,你可以使每个共享变量成为一个哈希表   用户ID(Globals!UserID)。

Embedded Code in Reporting Services

  

...如果多个用户同时使用此代码执行报告,两者都是   报告将更改相同的Count字段(这就是共享字段的原因)。您   不想调试这些类型的交互 - 只使用共享功能   局部变量(传递ByVal的变量或在函数体中声明的变量)。

我想这个想法是在报告生成服务器上加载报告并且Code模块是静态类。如果第二个客户端足够快地请求与另一个客户端相同的报告,则它将连接到该静态类的同一实例。 (如果我弄错了,欢迎你更正我的描述。)

所以,我正在继续使用哈希表来保持隔离。我计划将哈希键作为一个名为InstanceID的内部报表参数,默认为=Guid.NewGuid().ToString()

通过我对此研究的部分方式,我发现它更复杂,因为Hashtables不是线程安全的,根据Maintaining State in Reporting Services

该作者的代码类似于我正在开发的代码,只有整个线程安全的东西完全超出我的经验。我需要花费数小时的时间来研究所有这些,并将合理的代码放在一起,我可以对它充满信心并且表现良好。

所以在我走得太远之前,我想知道是否还有其他人已经走过这条道路并且可以给我一些建议。这是我到目前为止的代码:

Private Shared Data As New System.Collections.Hashtable()

Public Shared Function Initialize() As String
   If Not Data.ContainsKey(Parameters!InstanceID.Value) Then
      Data.Add(Parameters!InstanceID.Value, New System.Collections.Hashtable())
   End If
   LetValue("SomethingCount", 0)
   Return ""
End Function

Private Shared Function GetValue(ByVal Name As String) As Object
   Return Data.Item(Parameters!InstanceID.Value).Item(Name)
End Function

Private Shared Sub LetValue(ByVal Name As String, ByVal Value As Object)
   Dim V As System.Collections.Hashtable = Data.Item(Parameters!InstanceID.Value)
   If Not V.ContainsKey(Name) Then
      V.Add(Name, Value)
   Else
      V.Item(Name) = Value
   End If
End Sub

Public Shared Function SomethingCount() As Long
   SomethingCount = GetValue("SomethingCount") + 1
   LetValue("SomethingCount", SomethingCount)
End Function
  1. 我最关心的是线程安全。我或许可以弄清楚下面的其他问题,但我对此没有经验,我知道这是一个容易出错的区域。上面的链接使用方法Dim _sht as System.Collections.Hashtable = System.Collections.Hashtable.Synchronized(_hashtable)。那是最好的吗? Mutex怎么样?信号?我没有这方面的经验。

  2. 我认为Hashtable的命名空间System.Collections是正确的,但是我在报告中添加System.Collections作为参考时遇到了麻烦,试图修复我当前的错误“无法加载文件或程序集” System.Collections中”。当我浏览添加引用时,它不是可供选择的组件。

  3. 我刚刚确认我可以从参数的默认值表达式调用代码,所以我将把Initialize代码放在那里。我也刚刚发现了OnInit程序,但它有自己的研究和解决方法:the Parameters collection may not be referenced from the OnInit method during parameter initialization

  4. 我不确定将Data变量声明为New,也许它应该只在初始化程序中实例化(如果尚未完成)(但我担心竞争条件,因为检查它是空的和实例化它。)

  5. 我还有一个关于Shared关键字的问题。在所有情况下都有必要吗?如果我将其从函数声明中删除,我会收到错误,但是当我将它从变量声明中删除时,会出现。测试多个同时报告执行很困难......有人可以解释SSRS代码背景下具体共享意味着什么吗?

  6. 有没有更好的方法来初始化变量?我应该为GetValue函数提供第二个参数,如果它发现哈希表中不存在该变量,那么它是默认值吗?

  7. 我在实现中选择嵌套的Hashtables,或者将我的InstanceID连接到变量名称以获得平面哈希表是不是更好?

  8. 我非常感谢我在这里提出的任何方面的指导,想法和/或批评。

    谢谢!

    埃里克

1 个答案:

答案 0 :(得分:1)

您的代码看起来很好。对于线程安全,只需要同步根(共享)哈希表数据。如果您想避免使用InstanceID,可以使用Globals.ExecutionTimeUser.UserID连接。

基本上我认为你只想改变这样的初始化:

Private Shared Data As System.Collections.Hashtable 

If Data Is Nothing Then
   Set Data = Hashtable.Synchronized(New System.Collections.Hashtable())
End If

包含的哈希表一般只能由一个线程使用,但如果有疑问,你也可以同步它们。