Sql server SSRS代码共享变量和同步报告执行

Sql server SSRS代码共享变量和同步报告执行,sql-server,vb.net,optimization,reporting-services,thread-safety,Sql Server,Vb.net,Optimization,Reporting Services,Thread Safety,我们有一些SSR报告,当两个SSR紧密结合在一起执行时失败 我发现,如果一个SSRS报告的两个实例同时运行,那么在类级别(而不是在函数内部)声明的任何代码变量都可能发生冲突。我怀疑这可能是我们报告失败的原因,我正在研究一个潜在的修复方法 我们之所以使用SSRS的代码部分,完全是为了自定义组和页眉计算。该代码从文本框中的表达式调用,并返回当前标签应该是什么。代码需要保持状态以记住最后的头值是什么,以便在未知时返回它,或者存储新的头值以供重用 注意:以下是关于变量冲突问题的参考资料: 委员会: 因为

我们有一些SSR报告,当两个SSR紧密结合在一起执行时失败

我发现,如果一个SSRS报告的两个实例同时运行,那么在类级别(而不是在函数内部)声明的任何代码变量都可能发生冲突。我怀疑这可能是我们报告失败的原因,我正在研究一个潜在的修复方法

我们之所以使用SSRS的代码部分,完全是为了自定义组和页眉计算。该代码从文本框中的表达式调用,并返回当前标签应该是什么。代码需要保持状态以记住最后的头值是什么,以便在未知时返回它,或者存储新的头值以供重用

注意:以下是关于变量冲突问题的参考资料:

委员会:

因为它使用静态变量,如果两个人同时运行报告 此时,一个变量打破另一个变量状态的可能性很小(在SQL 2000中, 由于两个用户同时对同一报告进行分页,有时会发生这种情况 同时,不仅仅是因为同时执行)。如果你需要100% 为了避免这种情况,您可以基于 用户ID(Globals!UserID)

:

。。。如果多个用户同时使用此代码执行报告,则 报告将更改相同的计数字段(这就是为什么它是一个共享字段)。你 不想调试这些类型的交互-只使用 局部变量(通过val传递或在函数体中声明的变量)

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

所以,我开始考虑使用散列表来隔离事物。我计划将散列键作为名为InstanceID的内部报表参数,默认值为
=Guid.NewGuid().ToString()

不过,在我对此进行研究的过程中,我发现它更为复杂,因为哈希表不是线程安全的

这位作者的代码与我正在开发的代码类似,只是整个线程安全问题完全超出了我的经验。我需要花上几个小时来研究所有这些,并整理出合理的代码,让我有信心并且性能良好

所以,在我走得更远之前,我想知道是否还有其他人已经走上了这条道路,可以给我一些建议。以下是我目前掌握的代码:

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
  • 我最关心的是线程安全。我可能能够解决下面的其余问题,但我没有这方面的经验,我知道这是一个容易出错的领域。上面的链接使用方法
    Dim\u sht作为System.Collections.Hashtable=System.Collections.Hashtable.Synchronized(\u Hashtable)
    。那是最好的吗?互斥呢?信号灯?我在这方面没有经验

  • 我认为哈希表的名称空间System.Collections是正确的,但我在报告中添加System.Collections作为引用时遇到了问题,无法解决当前出现的错误“无法加载文件或程序集'System.Collections'”。当我浏览添加引用时,它不是可供选择的组件

  • 我刚刚确认我可以从参数的默认值表达式调用代码,所以我将把我的初始化代码放在那里。我也刚刚了解了OnInit过程,但这有自己的研究和解决方法:

  • 我不确定是否要将数据变量声明为新的,如果还没有完成,可能应该只在初始值设定项中实例化它(但是我担心争用条件,因为检查它是否为空和实例化它之间存在延迟)

  • 我还有一个关于共享关键字的问题。在所有情况下都有必要吗?如果我不使用函数声明,我会出错,但如果我不使用变量声明,它似乎会起作用。测试多个同时执行的报告很困难。。。有人能解释一下共享在SSRS代码中的具体含义吗

  • 有没有更好的方法初始化变量?我应该为GetValue函数提供第二个参数吗?如果它发现hashtable中还不存在该变量,那么该参数就是要使用的默认值

  • 按照我在实现中的选择,使用嵌套的哈希表更好,还是将InstanceID与变量名连接起来以使用平面哈希表更好

  • 我非常感谢您对我在这里介绍的任何方面的指导、想法和/或批评

    谢谢大家!


    Erik你的代码看起来不错。为了线程安全,只需要同步根(共享)哈希表数据。如果要避免使用InstanceID,可以使用连接的
    Globals.ExecutionTime
    User.UserID

    基本上,我认为您只需要更改为如下初始化:

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

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

    一次有太多问题吗?我应该发布7个不同的问题吗?这个问题太本地化了。没有人会对你的代码有经验。如果你在变量方面有问题,你可能会问“如何在SSR中使用变量而不发生冲突”,等等。我没有阅读全部内容,但你尝试过缓存报告吗?@DForck我想我理解你的意思,但我不认为缓存是一种选择。报告在每次执行时都必须是最新的。好的,我想这可能是工作要求。谢谢你的帮助。是苏