AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 128695
Accepted
Bogdan Bogdanov
Bogdan Bogdanov
Asked: 2016-02-10 00:42:22 +0800 CST2016-02-10 00:42:22 +0800 CST 2016-02-10 00:42:22 +0800 CST

SQL 2012 CLR 错误:“在进入...之前处于活动状态的上下文事务”?

  • 772

我遇到了奇怪的错误SQL 2012and CLR:

在进入用户定义的例程、触发器或聚合“我的例程”之前处于活动状态的上下文事务已在其中结束,这是不允许的。更改应用程序逻辑以强制执行严格的事务嵌套。

我不知道可能是什么问题。谁能给我一些搜索的方向?

一般来说,我有 SQL 存储过程,在UPDATE子句中我调用scalar CLR function. 该函数获取 2 个xml字符串:一个用于验证xml,另一个用于xsd验证。该函数在查询中被多次调用。

编辑:

错误信息:

错误号:3991

错误严重性:16

错误状态:1

错误过程:sproc_XXX

错误行:297

错误消息:在进入用户定义的例程、触发器或聚合“CLR_XXX_Xml”之前处于活动状态的上下文事务已在其中结束,这是不允许的。更改应用程序逻辑以强制执行严格的事务嵌套。

编辑2:

我发现了问题。当我们使用CLRvalidateXML时,我们将第一个参数设置为XSD名称。然后在我们从 SQL Server中CLR提取模式。XSD在我们的例子中,我们有空字符串作为XSD名称,但即使我们有try / catch错误也向上传递到 SQL Server 存储过程。

我们的函数返回0 / 1,因此必须使用错误代码更新带有 0 的记录。

但在这种情况下,我们在 SQL 中收到异常。

我的代码是:

用于更新的 SQL

UPDATE FR
SET ErrorCode = 'OUR ERROR CODE'
FROM dbo.DataTable FR
INNER JOIN dbo.TempTable FRN ON (FRN.SessionGUID = @sSessionGUID)
    AND (FRN.IDLog = FR.IDLog)
    AND (FRN.UniqueID = FR.UniqueID)
    AND (
        (FRN.Template LIKE '%##%')
        OR (PANI_Core.dbo.funCLRs_CheckXML('schRPT_' + @sSchema + '_Peliminary', 
     FRN.Template) <> 1)
        OR (NULLIF(FRN.Template, '') IS NULL)
        OR (
            (TRY_CONVERT(DATE, FRN.ExpirationDate) IS NULL)
            AND (NULLIF(FRN.ExpirationDate, '') IS NOT NULL)
            )
        OR (
            (TRY_CONVERT(VARCHAR(35), FRN.EGN) IS NULL)
            AND (NULLIF(FRN.EGN, '') IS NOT NULL)
            )
        OR (NULLIF(FRN.EGN, '') IS NULL)
        OR (
            (TRY_CONVERT(MONEY, FRN.Amount) IS NULL)
            AND (NULLIF(FRN.Amount, '') IS NOT NULL)
            )
        OR (NULLIF(FRN.Amount, '') IS NULL)
        OR (
            (TRY_CONVERT(VARCHAR(32), FRN.UniqueClientID) IS NULL)
            AND (NULLIF(FRN.UniqueCID, '') IS NOT NULL)
            )
        OR (NULLIF(FRN.UniqueCID, '') IS NULL)
        )
WHERE (FR.IDLog = @IDLog)
    AND (FR.ErrorCode IS NULL);

CLR 代码:

public static SqlBoolean funCLRs_CheckXml(SqlString XsdSchemaString, SqlString ValueString)
{
    XmlDocument asset1 = new XmlDocument();
    XmlSchema schema1 = new XmlSchema();
    System.Text.StringBuilder o = new System.Text.StringBuilder();
    using (SqlConnection sqlLocalConn = new SqlConnection("context connection=true;"))
    {
        try
        {
            if (XsdSchemaString.ToString().Length == 0)
            {
                try
                {
                    asset1.LoadXml(ValueString.ToString());
                    asset1 = null;
                    return new SqlBoolean(true);
                }
                catch (Exception ex)
                {
                    return new SqlBoolean(false);
                }
            }
            else
            {
                sqlLocalConn.Open();

                SqlCommand cmd = new SqlCommand("SELECT XML_SCHEMA_NAMESPACE (N'dbo', N'" + XsdSchemaString.ToString() + "')", sqlLocalConn);
                cmd.CommandTimeout = 240;

                SqlDataReader reader = cmd.ExecuteReader();
                if (reader.Read())
                {
                    SqlXml xmlData = reader.GetSqlXml(0);
                    using (XmlReader xmlReader = xmlData.CreateReader())
                    {
                        schema1 = XmlSchema.Read(xmlReader, ValidateSchema);
                    }

                    asset1.Schemas.Add(schema1);

                    XDocument oDoc = new XDocument();
                    oDoc = XDocument.Parse(ValueString.ToString());
                    oDoc.Descendants().Where(e => string.IsNullOrEmpty(e.Value)).Remove();

                    asset1.LoadXml(oDoc.FirstNode.ToString());
                    oDoc = null;

                    asset1.Validate((o1, e) =>
                    {
                        if (e.Severity == XmlSeverityType.Error)
                        {
                            o.AppendLine("Error: " + e.Message);
                        }
                    });

                    if (asset1.SchemaInfo.Validity == XmlSchemaValidity.Valid)
                    {
                        asset1 = null;
                        return new SqlBoolean(true);
                    }
                    else
                    {
                        asset1 = null;
                        return new SqlBoolean(false);
                    }
                }
                else
                {
                    asset1 = null;
                    return new SqlBoolean(false);
                }
            }
        }
        catch (Exception ex)
        {
            return new SqlBoolean(false);
        }
        finally
        {
            schema1 = null;
            asset1 = null;
            o = null;
        }
    }
}
transaction sql-server-2012
  • 1 1 个回答
  • 3345 Views

1 个回答

  • Voted
  1. Best Answer
    Solomon Rutzky
    2016-02-10T08:44:50+08:002016-02-10T08:44:50+08:00

    “在进入用户定义的例程、触发器或聚合之前处于活动状态的上下文事务“...”已在其中结束,这是不允许的。 ”错误的直接原因是:

    您正在调用XML_SCHEMA_NAMESPACE()内置函数,有时由于找不到指定的 XML 模式集合而失败。根据问题中的信息,当发生此错误时,您将传入一个空字符串,但传入与现有 XML 模式集合不匹配的任何字符串都会导致此错误。

    发生的情况是,当调用此 SQLCLR 函数(即UPDATE语句的事务)时,您当前处于事务中,并且失败XML_SCHEMA_NAMESPACE是批处理中止错误,在这种情况下事务会自动回滚(因此try...catch在.NET 代码在这里无能为力)。如果您有嵌套的存储过程调用,其中外部存储过程开始事务并且内部存储过程发出 aROLLBACK在这种情况@@TRANCOUNT下,退出内部存储过程时的值将低于它时,这实际上是相同的错误输入它,你会得到一个错误,指出 的起始值和结束值@@TRANCOUNT不一样。

    这是显示XML_SCHEMA_NAMESPACE失败是批处理(因此是事务)中止错误的示例代码:

    BEGIN TRAN;
    PRINT @@TRANCOUNT;
    DECLARE @SchemaCollectionName sysname = N'f';
    PRINT CONVERT(NVARCHAR(4000), XML_SCHEMA_NAMESPACE(N'dbo', @SchemaCollectionName));
    GO
    PRINT @@TRANCOUNT;
    ROLLBACK;
    

    回报:

    1
    消息 6314,级别 16,状态 1,第 4 行
    指定的集合在元数据中不存在:'f'
    0
    消息 3903,级别 16,状态 1,第 7 行
    ROLLBACK TRANSACTION 请求没有相应的 BEGIN TRANSACTION。

    此错误的根本原因是:

    您允许将值传递给XML_SCHEMA_NAMESPACE导致其出错的函数,特别是空字符串。

    此错误的修复方法是执行以下操作:

    1. 还要测试NULL仅包含空格的字符串值。这将防止由于NULL值(无论如何都会导致当前代码出错)以及由空格、制表符、回车等的任意组合填充的非空字符串引起的错误(该IsNullOrWhiteSpace方法检查所有 Unicode 空白字符)。将:替换
      if (XsdSchemaString.ToString().Length == 0)
      为:
      if (XsdSchemaString.IsNull || String.IsNullOrWhiteSpace(XsdSchemaString.Value))
    2. 在调用之前检查传入的 XML Schema Collection 名称是否存在,XML_SCHEMA_NAMESPACE以便仅在名称实际存在时才调用该函数。您可以在与当前相同的步骤中执行此操作,方法是将其SELECT包装在IF EXISTS:

      DECLARE @SchemaCollectionName NVARCHAR(128) = N'not here';
      IF (EXISTS(
              SELECT  *
              FROM        sys.xml_schema_collections
              WHERE   [schema_id] = SCHEMA_ID(N'dbo')
              AND     [name] = @SchemaCollectionName
              )
          )
      BEGIN
          SELECT XML_SCHEMA_NAMESPACE(N'dbo', @SchemaCollectionName) AS [MyXSD];
      END;
      

      这将防止由于不正确的非空、非仅空白值而导致的错误。不正确的值不会返回结果集,并且您的代码已经将其else作为if (reader.Read()).

    3. 虽然对这个问题并不重要,但最好参数化该查询。两个地方的示例代码都表明该函数确实接受 XML 模式集合名称的变量。
    • 2

相关问题

  • 闪回查询和序列化事务模式的区别?

  • 描述“持久事务”的正确术语是什么?

  • 为什么 Denali 序列应该比标识列表现更好?

  • SQL Server 不应该支持范围吗?

  • 什么是 SQL Server“德纳利”?什么是新的?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve