Одна и та же транзакция возвращает разные результаты, когда я запускался несколько раз - PullRequest
0 голосов
/ 30 августа 2018

Когда я использовал TiDB, мне было странно, когда я выполняю две транзакции одновременно. Я ожидал получить то же значение 2, что и MySQL, но все, что я получил, это 0, 2, 0, 2, 0, 2 ...

Для обеих баз данных tx_isolation имеет значение 'read-commit'. Поэтому вполне разумно, что оператор 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) вставляются изначально.

1 Ответ

0 голосов
/ 07 сентября 2018

Прежде всего:

Для TiDB только поддержка SNAPSHOT (последняя версия) Уровень изоляции транзакций . но он может видеть только подтвержденные данные до транзакции .

и TiDB также не будут обновлять одно и то же значение в транзакции , как MySQL и SQL Server и т. д.

Для MySQL , когда используется уровень изоляции READ COMMITTED , он будет читать совершенные данные, поэтому он будет читать другие транзакции зафиксированные данные.

Так как ваш фрагмент кода:

TiDB раунд 1 рабочий процесс:

               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 до пропустить обновление с тем же значением в Транзакции , но когда с другим значением он также может быть успешно обновлен, например, мы можем обновить b до другого значения в цикле, мы всегда можем получить последнее изменение b.

Так что, может быть, лучше сохранить такое же поведение между одинаковым значением и другим значением .

Я создал проблему для этого:

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

Ссылки:

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

...