【问题标题】:Same transaction returns different results when i ran multiply times当我多次运行时,相同的事务返回不同的结果
【发布时间】:2018-08-30 13:09:33
【问题描述】:

当我使用 TiDB 时,我发现当我同时运行两个事务时很奇怪。我期望得到与 MySQL 相同的值 2,但我得到的只是 0、2、0、2、0、2...

对于这两个数据库,tx_isolation 都设置为“已提交读”。所以 select 语句返回 2 是合理的,因为它已经提交了。

这是测试代码:

for i in range(10):
    conn1 = mysql.connector.connect(host='',
                                port=4000,
                                user='',
                                password='',
                                database='',
                                charset='utf8')
    conn2 = mysql.connector.connect(host='',
                                port=4000,
                                user='',
                                password='',
                                database='',
                                charset='utf8')

    cur1 = conn1.cursor()
    cur2 = conn2.cursor()

    conn1.start_transaction()
    conn2.start_transaction()

    cur2.execute("update t set b=%d where a=1" % 2)
    conn2.commit()

    cur1.execute("select b from t where a=1")
    a = cur1.fetchone()
    print(a)

    cur1.execute("update t set b=%d where a=1" % 0)
    conn1.commit()

    cur1.close()
    cur2.close()
    conn1.close()
    conn2.close()

表 t 是这样创建的:

CREATE TABLE `t` (
  `a` int(11) NOT NULL AUTO_INCREMENT,
  `b` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`)
) 

最初插入的是 (1,0)。

【问题讨论】:

    标签: tidb


    【解决方案1】:

    首先:

    TiDB 仅支持 SNAPSHOT(最新版本) 交易隔离级别。但它只能在事务开始之前看到提交的数据。

    和 TiDB 也不会在事务中更新相同的值, 比如MySQL和SQL Server等

    对于MySQL,当使用READ COMMITTED隔离级别时, 将读取 committed 数据,因此它将读取其他事务 提交的数据。

    所以你的代码 sn-p:

    TiDB 第一轮工作流程:

                   T1                                   T2
    
         +--------------------+
         | transaction start  |
         |      (b = 0)       |
         +---------+----------+
                   |
                   |
                   |                        +------------------------------+
                   | <----------------------+  update `b` to 2, and commit |
                   |                        +------------------------------+
                   |
                   |
       +-----------+-----------+
       | select b should be 0, |
       | since tidb will only  |
       | get the data before   |
       | transaction committed |
       +-----------+-----------+
                   |
                   v
    
    +------------------------------+
    |      update value to 0       |
    | (since 0 is equal to the     |
    | transaction started value,   |
    | tidb will ignore this update)|
    +------------------------------+
                                      +
                                      |
                                      |
                                      |
                                      v
    
                          +-------------------------+
                          |so finally `b` will be 2 |
                          +-------------------------+
    

    TiDB 第 2 轮工作流程:

                   T1                                   T2
    
         +--------------------+
         | transaction start  |
         |      (b = 2)       |
         +---------+----------+
                   |
                   |
                   |                        +------------------------------+
                   | <----------------------+  update `b` to 2, and commit |
                   |                        +------------------------------+
                   |
                   |
       +-----------+-----------+
       | select b should be 2, |
       | since tidb will only  |
       | get the data before   |
       | transaction committed |
       +-----------+-----------+
                   |
                   v
    
    +------------------------------+
    |      update value to 0       |
    | (since 0 is not equal to 2   |
    +------------------------------+
                                      +
                                      |
                                      |
                                      |
                                      v
    
                          +-------------------------+
                          |so finally `b` will be 0 |
                          +-------------------------+
    

    所以对于 TiDB 会输出如下:

    0, 2, 0, 2, 0, 2...
    

    MySQL 工作流程:

                          T1                                   T2
    
    
              +----------------------+
              |  transaction start   |
              |       ( b = 0 )      |
              +-----------+----------+
                          |
                          |
                          |
                          |                         +---------------------------+
                          |  <----------------------+update `b` to 2, and commit|
                          |                         +---------------------------+
                          |
                          |
                          v
    
    +--------------------------------------------+
    | select b should be 2,                      |
    | since use READ COMMITTED isolation level,  |
    | it will read committed data.               |
    +---------------------+----------------------+
                          |
                          |
                          v
    
               +--------------------+
               | update value to 0  |
               +--------------------+
                                            +
                                            |
                                            |
                                            |
                                            v
    
                                 +--------------------------+
                                 | so finally `b` will be 0 |
                                 +--------------------------+
    

    所以MySQL可以连续输出:

    2, 2, 2, 2...


    词尾

    我认为 TiDB 在 Transaction 中跳过更新相同的值 很奇怪,但是当使用 不同的值时 也可以更新成功,就像我们可以在循环中将b 更新为不同的值,我们总是可以得到最新的更改 b.

    所以也许最好在相同的值和不同的值之间保持相同的行为。

    我为此创建了一个问题:

    https://github.com/pingcap/tidb/issues/7644

    参考资料:

    https://github.com/pingcap/docs/blob/master/sql/transaction-isolation.md

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 2016-09-29
      • 1970-01-01
      • 2020-05-15
      相关资源
      最近更新 更多