【问题标题】:Why does DELETE statement fail silently with MySQL Connector/net when it works in MySql Workbench and PHP/PDO?为什么在 MySql Workbench 和 PHP/PDO 中使用 MySQL Connector/net 时,DELETE 语句会静默失败?
【发布时间】:2018-11-09 11:17:49
【问题描述】:

我有一个 MariaDB 数据库,其中包含一个表,其中包含有关在 CentOS 7 服务器上运行的移动设备(android 和 ios)的信息,该服务器具有 Mono JIT 编译器版本 5.4.0.201 和 MySql Connector/NET(最新版本 8.0.13)。

一切都很好,除了我无法通过连接器/NET 从设备表中删除基于推送令牌的设备。表定义如下:

CREATE TABLE `Devices` (
  `idDevices` int(11) NOT NULL AUTO_INCREMENT,
  `notificationId` varchar(160) DEFAULT NULL,
  `deviceId` varchar(64) NOT NULL,
  `isAndroid` tinyint(1) NOT NULL,
  `deviceModel` varchar(64) DEFAULT NULL,
  `appMajor` tinyint(4) DEFAULT NULL,
  `appMinor` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`idDevices`),
  UNIQUE KEY `isAndroid` (`isAndroid`,`deviceId`),
  UNIQUE KEY `notificationId_UNIQUE` (`isAndroid`,`notificationId`),
  KEY `appVersion` (`appMajor`,`appMinor`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

当我从 Mono 应用程序运行 DELETE 语句时,没有发生异常,但从 ExecuteNonQuery() 返回的 int 值始终为 0,并且没有从表中删除任何行。 mariadb.log (log_warning=4) 中不记录任何错误或警告。 如果我将完全相同的 SQL 语句复制到 MySql Workbench 并在那里执行该语句,则会按预期删除行。 如果我创建一个 PHP 脚本并使用 PDO 连接到同一个数据库,它也可以按预期工作。所有三个测试用例都使用相同的用户(root)。所以这似乎是特定于 Connector/NET 的问题

            var tokenCount = 0;
            var sql = new StringBuilder ("DELETE FROM Devices WHERE isAndroid = 0 AND notificationId IN ('");

            while (...) {
                sql.Append (token);
                sql.Append ("','");
                tokenCount++;
            }

            sql.Length -= 2;
            sql.Append (')');

            using (var connection = new MySqlConnection (connectionString)) {
                connection.Open ();
                using (var command = new MySqlCommand (sql.ToString (), connection)) {
                    var affectedRows = command.ExecuteNonQuery ();
                    if (affectedRows != tokenCount) {
                        //Always logs affectedRows(0)
                        log.Warn ($"Remove tokenCount({tokenCount}) != affectedRows({affectedRows}). sql={sql}");
                    }
                }
            }

更新:我启用了 general_log,我看到正确的数据库已初始化并且语句已运行 - 但表没有更改!日志输出:

        3 Init DB   mydb
        3 Query DELETE FROM Devices WHERE isAndroid = 0 AND notificationId IN ('002B1C477DB4F20868D157A806DF70E05D61D3950562C03E092707CA9C5CCF23')

更新 #2: 我尝试使用相同的 WHERE 子句将 DELETE 语句更改为 SELECT 语句,你瞧,没有返回任何行。因此,由于某种原因,notificationId 上的匹配似乎不起作用。会不会是编码问题?为什么它可以在其他客户端运行,但在我的 Connector/NET 客户端却不行?

【问题讨论】:

  • 我不确定,但是根据 mariadb 的知识:对于单表语法,DELETE 语句从 tbl_name 中删除行并返回已删除行数的计数。这个计数可以通过调用 ROW_COUNT() 函数获得。 see 。您没有得到受影响的行数。而sql的价值是什么
  • @KevinKouketsu 正如我所说,问题不在于返回的值,问题在于没有删除任何行。所以返回值是正确的,但是语句没有被执行。
  • @mjwills 示例值为:“DELETE FROM Devices WHERE isAndroid = 0 AND notificationId IN ('08C2D56EFA0372DB9F533FE791B2F2E2DDFFC73D4198641E5A440BBE8BC12110')”。但我的问题不在于我的 SQL 语句,因为它不会引发异常,并且在其他连接器和工作台中运行良好。问题是该语句被完全忽略。
  • 在您的 SQL 工具中,请运行此查询并使用结果更新您的问题 - SELECT * FROM Devices WHERE isAndroid = 0 AND notificationId IN ('08C2D56EFA0372DB9F533FE791B2F2E2DDFFC73D4198641E5A440BBE8BC12110')"
  • 奇怪,也许启用 full query logging 并将 .Net 调用与 Workbench 调用进行比较

标签: c# mysql mono connector-net


【解决方案1】:

好的,经过几个小时的调试,我发现了问题。原来它与连接器/网络无关。问题在于我是如何构建令牌的,我不小心附加了一些不会在我的 log4net 日志中打印的字符,所以 SQL 在客户端似乎没问题——但是发送到数据库服务器的实际 SQL 字符串包含无效令牌!

【讨论】:

    猜你喜欢
    • 1970-01-01
    相关资源
    最近更新 更多