AlwaysEncrypted插入间歇性地失败

时间:2019-02-13 00:03:14

标签: c# sql-server always-encrypted

我们使用Microsoft SQL的AlwaysEncrypted功能已有一年多了。到现在为止,它一直完美无瑕。 以前,我们只有很少几列被加密(4)。一周前,我们在另外11列上实现了加密,因此我们仍然很少使用它。

不幸的是,我们对带有加密列的表的某些“ INSERT”命令失败了,但只是间歇性地。这些命令正在由Web服务器(IIS服务器)运行。我可以运行该命令,使其失败,然后在引发异常后立即在同一进程(Web服务器已简单地处理了该异常)中运行相同的命令,并且成功。

服务器二进制文件是用c#编写的,命令绝对是微不足道的。例如,此命令的执行失败:

INSERT INTO [dbo].[someTable] ( [COL1], [COL2], [COL3] ) VALUES ( @COL1_0, @COL2_0, @COL3_0 )

其中所有三列(COL1,COL2和COL3)均已加密,并且[someTable]仅包含这三列,所有varchar(64)和一个整数标识列。

c#代码(解释为)

        SqlCommand cmd = new SqlCommand();
        cmd.Connection = GetOpenConnection("Data Source=REDACTED;Integrated Security=SSPI;Column Encryption Setting=enabled;Initial Catalog=PRODUCTION");
        cmd.CommandText = "INSERT INTO [dbo].[someTable] ( [COL1], [COL2], [COL3] ) VALUES ( @COL1_0, @COL2_0, @COL3_0 )";
        cmd.CommandType = CommandType.Text;
        cmd.Transaction = m_Transaction;            

        foreach(string[] paramData in inputParamsData) //3 of these
        {
                                                      //@COLx_0
            SqlParameter param = new SqlParameter(paramData[0], SqlDbType.VarChar, 64);
            param.Value = paramData[1];
            cmd.Parameters.Add(param);
        }
        string msg = "Preparing";
        try
        {
            cmd.Prepare();
            msg = "Executing";
            return cmd.ExecuteNonQuery();
        }
        catch (Exception ex)
        {
            if (ex.Message.Contains("Operand type clash"))
            {
                log.Error($"{msg} non-query", ex);
                log.Error("Parameters in command");
                foreach (var obj in command.Parameters)
                {
                    SqlParameter param = obj as SqlParameter;
                    if (param != null)
                    {
                        log.ErrorFormat("Param name: {0}, length: {1}", param.ParameterName, param.Size);
                    }
                }
            }
            throw;
        }

ExecuteNonQuery()上执行失败(尽管异常消息文本表明它无法“准备”查询,但是通过检查日志消息可以清楚地知道Prepare成功并且{{1 }}失败。) 我们得到的日志是:

ExecuteNonQuery

可以看到确实已正确设置了参数大小。唯一被其加密的列是“ FIGI”列,它是varchar(64)列,并且该参数似乎已正确设置。

我们有一个Microsoft SQL Server Enterprise(64位),版本13.0.5026.0。 IIS服务器具有.NET 4.6.1。

有人经历过这样的间歇性故障吗?是否有人在哪里可以找到问题的指针?

我注意到类2019-02-21 23:15:43,046 ERROR [15:xxx.DbConnectionWrapper`6] - Executing non-query System.Data.SqlClient.SqlException (0x80131904): Operand type clash: varchar is incompatible with varchar(64) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'ColumnKey_20180605_123456', column_encryption_key_database_name = 'Production') collation_name = 'Latin1_General_BIN2' Statement(s) could not be prepared. ... Error Number:206,State:2,Class:16 2019-02-21 23:15:43,067 ERROR [15:xxx.DbConnectionWrapper`6] - Parameters in command 2019-02-21 23:15:43,069 ERROR [15:xxx.DbConnectionWrapper`6] - Param name: @FIGI_0, length: 64 具有属性SqlParameter,但是很少有文档说明何时,何地或如何使用此参数。谁能解释它的用途或为我提供不错的文档?

编辑:事实证明,间歇性更差。它每周仅失败一次。鉴于以下有关参数大小的注释,我在失败时添加了一些调试日志记录,结果如上。

0 个答案:

没有答案