【问题标题】:C# .NET MySQL (MariaDB) Not Saving Data Yet Returning SucessC# .NET MySQL (MariaDB) 未保存数据但返回成功
【发布时间】:2019-03-03 16:13:33
【问题描述】:

即使 MysqlClient 正在返回成功和更新的行数,生产中的间歇性数据(在本地、开发或 UAT 环境中不可重复)也不会保存到数据库中。

生产的应用服务器是IIS 7 on Windows Server 2008

此应用程序服务器与 2 个独立的数据库服务器通信。

Ubuntu 上的一个 Linux servername 4.15.0-23-generic #25-Ubuntu SMP Wed May 23 18:02:16 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux +-------------------------+----------------------------------+ | Variable_name | Value | +-------------------------+----------------------------------+ | innodb_version | 5.6.39-83.1 | | protocol_version | 10 | | slave_type_conversions | | | version | 10.1.34-MariaDB-0ubuntu0.18.04.1 | | version_comment | Ubuntu 18.04 | | version_compile_machine | x86_64 | | version_compile_os | debian-linux-gnu | | version_malloc_library | system jemalloc | | version_ssl_library | YaSSL 2.4.4 | | wsrep_patch_version | wsrep_25.23 | +-------------------------+----------------------------------+

另一个在 Fedora Linux servername 4.8.13-100.fc23.x86_64 #1 SMP Fri Dec 9 14:51:40 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

+-------------------------+-----------------+ | Variable_name | Value | +-------------------------+-----------------+ | innodb_version | 5.6.32-79.0 | | protocol_version | 10 | | slave_type_conversions | | | version | 10.0.28-MariaDB | | version_comment | MariaDB Server | | version_compile_machine | x86_64 | | version_compile_os | Linux | | version_malloc_library | system | +-------------------------+-----------------+

嘿,请不要询问完全不同的数据库服务器。无论如何,它们都表现出相同的问题。

应用程序位于.NET 4.5 并使用MysqlConnector Mysql.Data dll 6.9.4 与两个数据库进行通信。

偶尔(在重负载下(就系统通常获得的负载而言);大约 25 个并发用户)系统将开始不将更改保存到数据库中,即使应用程序从诸如 int x = Sqlcmd.ExecuteNonQuery(); 之类的代码返回成功也是如此其中 x 是更新的行数。

这将发生在非常基本的 Mysql 更新中,例如

MySqlConnection conn = new MySqlConnection(TheConnectionString()); conn.Open(); try { string Query = "DELETE FROM A_TABLE WHERE USERID = '" + UserID + "'"; MySqlCommand Sqlcmd = new MySqlCommand(Query, conn); Sqlcmd.CommandText = Query; Sqlcmd.ExecuteNonQuery(); } finally { if (conn != null) { conn.Close(); conn.Dispose(); } }

请忽略明显写得不好的容易出现sql注入的sql语句。

其他数据库交互方式(使用事务)也表现出相同的行为。

    //Create and Instantiate the Connection
        sqlConnection = new MySqlConnection(strConnect);
        sqlConnection.Open();

        //With Transaction
        if (bWithTrans == true)
        {
            sqlTransaction = sqlConnection.BeginTransaction();
            //sqlTransaction.IsolationLevel = IsolationLevel.
            bRollBack = false; // Reset indicator
        }

        sqlCommand = new MySqlCommand(qryString, sqlConnection);
        sqlCommand.CommandText = qryString;

        //With Transaction
        if (bWithTrans == true)
        {
            sqlCommand.Transaction = sqlTransaction;
        }
...
...
       if (IsInTransaction())
        {
            if (bRollBack == true)
            {
                sqlTransaction.Rollback();
            }
            else
            {
                sqlTransaction.Commit();
            }
            sqlTransaction.Connection.Close();
            sqlTransaction.Connection.Dispose();
            sqlTransaction = null;
        }

上面我省略了很多代码(例如关闭部分)。请忽略缺少using {} 语句(我99% 确定每个连接都已关闭。)

在不保存数据期间,select * from information_schema.innodb_trx中出现以下内容

*************************** 1. row ***************************
                    trx_id: 302303150
                 trx_state: RUNNING
               trx_started: 2018-09-27 08:56:45
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 117343
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 360
           trx_rows_locked: 0
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 1. row ***************************
                    trx_id: 302303150
                 trx_state: RUNNING
               trx_started: 2018-09-27 08:56:45
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 117343
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 360
           trx_rows_locked: 0
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
          trx_is_read_only: 0
trx_autocommit_non_locking: 0

看到trx_query: NULL 很奇怪...我有一个脚本每 0.1 秒打印一次这个表,它只会在数据没有保存到数据库时显示trx_query: NULL(但报告它是.)

在此期间,show engine innodb status 在 TRANSACTIONS 部分生成此信息...

------------
TRANSACTIONS
------------
Trx id counter 147254697
Purge done for trx's n:o < 147254674 undo n:o < 0 state: running but idle
History list length 30
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 222904, OS thread handle 0x7f7a6e08b700, query id 617593737 localhost root init
show engine innodb status
---TRANSACTION 147254688, not started
MySQL thread id 222902, OS thread handle 0x7f7a23a5f700, query id 617593732 10.22.18.39 DB_NAME
---TRANSACTION 147254696, not started
MySQL thread id 222901, OS thread handle 0x7f7a239c9700, query id 617593736 10.22.18.39 DB_NAME
---TRANSACTION 147254644, not started
MySQL thread id 222900, OS thread handle 0x7f7a6e027700, query id 617593526 10.22.18.39 DB_NAME
---TRANSACTION 147254684, not started
MySQL thread id 222897, OS thread handle 0x7f7a6b4e9700, query id 617593709 10.22.18.39 DB_NAME
---TRANSACTION 147240473, not started
MySQL thread id 126445, OS thread handle 0x7f7a23af5700, query id 617593614 10.22.18.41 DB_NAME
---TRANSACTION 84024323, not started
MySQL thread id 1, OS thread handle 0x7f7a6e185700, query id 0 Waiting for background binlog tasks
---TRANSACTION 147254695, ACTIVE 1 sec fetching rows
mysql tables in use 1, locked 0
MySQL thread id 222898, OS thread handle 0x7f7a239fb700, query id 617593734 10.22.18.39 DB_NAME Sending data
SELECT COUNT(*) FROM TABLE I'M HIDING FOR PRIVACY
Trx read view will not see trx with id >= 147254696, sees < 147254696
Trx #rec lock waits 0 #table lock waits 0
Trx total rec lock wait time 0 SEC
Trx total table lock wait time 0 SEC

我没有看到任何关于死锁的情况。

我尝试过的...

  • 由于数据库的操作系统和版本不同,我有一个 很难相信这是一个 Mysql (MariaDB) 问题。
  • 我尝试将 Mysql 连接器 dll 从 6.9.4 更改为 6.9.10 和 6.9.12
  • 我已将应用程序设置为每 1 小时回收一次应用程序池 IIS,回收1分钟后出现问题。
  • 我已经注释掉了 .beginTransaction() 的东西,所以 默认 AUTO-COMMIT 在每个ExecuteNonQuery() 之后执行

有人有什么想法吗?

谢谢

**edit 这里是记录到文件的查询日志(我编辑了 sql 以删除表/列名以保护隐私)

245133 Query    ROLLBACK
                245671 Connect  root@localhost as anonymous on
                245671 Query    select * from information_schema.innodb_trx
                244093 Query    ROLLBACK
                245671 Quit
                245133 Init DB  DB_NAME
                245133 Query    SELECT `DESC` as Status FROM TABLE WHERE REC_NUM != 2 ORDER BY `REC_NUM`
                245133 Query    ROLLBACK
                244093 Init DB  DB_NAME
                244093 Query    SELECT COLUMN FROM TABLE WHERE COLUMN IN (SELECT COLUMN FROM TABLE WHERE STATUSCODE = 3) ORDER BY COLUMN
                244093 Query    ROLLBACK
                245133 Init DB  DB_NAME
                245133 Query    SELECT COLUMN FROM TABLE GROUP BY COLUMN ORDER BY COLUMN
                245133 Query    ROLLBACK
                244093 Init DB  DB_NAME
                244093 Query    SELECT COLUMN as Status FROM TABLE WHERE COLUMN <> 1 AND COLUMN <> 2 AND COLUMN <> 4 AND COLUMN <> 10 AND COLUMN <> 11
AND COLUMN <> 12 AND COLUMN <> 13  AND COLUMN <> 15 ORDER BY REC_NUM
                244093 Query    ROLLBACK
                245133 Init DB  DB_NAME
                245133 Query    SELECT COLUMN FROM TABLE WHERE COLUMN = 'DB_NAME'
                245133 Query    ROLLBACK
                245248 Query    ROLLBACK
                244093 Init DB  DB_NAME
                245133 Init DB  DB_NAME

看到这么多 ROLLBACKS 真是太疯狂了……这可能是什么原因造成的。在我下面的评论中,我在 app_server > db_server 中的 tcpdump 中显示 ROLLBACK,因此启动这些回滚的不是数据库。

【问题讨论】:

  • 我的猜测是抛出异常并回滚事务。你应该添加一些日志来找出答案。
  • @DavidLibido 感谢您的评论。即使不使用事务,数据也不会保存。
  • 我不能怀疑回滚,但是如果没有明确的.rollback(),回滚会发生吗?...这里是数据库服务器的tcpdump,它显示回滚...13:57:58.830419 IP 10.22.18.39.49804 &gt; 10.22.18.246.3306: Flags [P.], seq 242305:242318, ack 3237214, win 508, length 13 0x0000: 4500 0035 06d2 4000 8006 baa8 0a16 1227 E..5..@........' 0x0010: 0a16 12f6 c28c 0cea c7e1 07c4 19e6 d958 ...............X 0x0020: 5018 01fc adfb 0000 0900 0000 0352 4f4c P............ROL 0x0030: 4c42 4143 4b LBACK跨度>
  • 是的,如果未提交事务(可能是由于异常),它最终会回滚。
  • 您提到了 SQL 注入漏洞,以及缺少的using 连接块;但是命令和事务也是一次性的,所以也应该在using 块中。一旦这些都到位,您将不需要关闭或处置连接。从问题中的代码来看,只有在使用事务时才会关闭连接。

标签: c# mysql asp.net .net mariadb


【解决方案1】:
SELECT  COLUMN
    FROM  TABLE
    WHERE  COLUMN IN (
        SELECT  COLUMN
            FROM  TABLE
            WHERE  STATUSCODE = 3
                     )
    ORDER BY  COLUMN

-->

SELECT column
    FROM table
    WHERE statuscode = 3
    ORDER BY column;

(如果确实有两个不同表,那么在您的问题中明确说明。在这种情况下,改进后的查询需要JOIN。)

SELECT  COLUMN
    FROM  TABLE
    GROUP BY  COLUMN
    ORDER BY  COLUMN

-->

SELECT DISTINCT column
    FROM table
    ORDER BY column

SELECT  COLUMN as Status
    FROM  TABLE
    WHERE  COLUMN <> 1
      AND  COLUMN <> 2
      AND  COLUMN <> 4
      AND  COLUMN <> 10
      AND  COLUMN <> 11
      AND  COLUMN <> 12
      AND  COLUMN <> 13
      AND  COLUMN <> 15
    ORDER BY  REC_NUM

-->

SELECT column AS Status
    FROM table
    WHERE column NOT IN (1,2,4,10,11,12,13,15)
    ORDER BY rec_num

Why do this; the answer is obviously 'DB_NAME':

SELECT column FROM table WHERE column = 'DB_NAME'.

【讨论】:

    【解决方案2】:

    好的,我相信我找到了问题。

    应用程序经常调用的一个非常常见的存储过程中包含此语句...

    START TRANSACTION;
    SET AUTOCOMMIT = 0;
    

    我从另一篇帖子中了解到SET AUTOCOMMIT = 0 是不必要的(而且很可能是我的罪魁祸首。)

    在我运行 SP 之前,show variables like 'autocommit' 在 SP 运行之后返回 ON,它说 OFF

    我的理论是,调用该 SP 的连接将其自动提交会话变量设置为 OFF,然后返回到池中。后来,当一个连接从池中抓取该会话时,它开始回滚每个语句,因为autocommit 仍然关闭,并且从未发送过明确的COMMIT;

    有人有这方面的经验吗?

    【讨论】:

    • 谁的“连接池”?如果无法重置所有VARIABLES,请不要使用它。
    猜你喜欢
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 2023-01-11
    • 2013-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多