Уровень изоляции не меняется, даже если установить "SERIALIZABLE" в 'OPTIONS' в settings.py в Django

Следуя документации , я установил SERIALIZABLE уровень изоляции на 'OPTIONS' в settings.py для PostgreSQL, как показано ниже. * Я использую Django 3.2.16 на Windows 11:

# "settings.py"

import psycopg2.extensions

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
    },
    'OPTIONS': { # ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   Here   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
        'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
    },
}

Затем я создал person таблицу с id и name с models.py как показано ниже:

person таблица:

id name
1 John
2 David
# "store/models.py"

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=30)

Затем я создал и запустил тестовый код non-repeatable read, который запускает две транзакции с двумя потоками одновременно, как показано ниже:

# "store/views.py"

from django.db import transaction
from time import sleep
from .models import Person
from threading import Thread
from django.http import HttpResponse

@transaction.atomic
def transaction1(flow):
    while True:
        while True:
            if flow[0] == "Step 1":
                sleep(0.1)
                print("<T1", flow[0] + ">", "BEGIN")
                flow[0] = "Step 2"
                break
        
        while True:
            if flow[0] == "Step 2":
                sleep(0.1)
                print("<T1", flow[0] + ">", "SELECT")
                person = Person.objects.get(id=2)
                print(person.id, person.name)
                flow[0] = "Step 3"
                break

        while True:
            if flow[0] == "Step 6":
                sleep(0.1)
                print("<T1", flow[0] + ">", "SELECT")                
                person = Person.objects.get(id=2)
                print(person.id, person.name)
                flow[0] = "Step 7"
                break
        
        while True:
            if flow[0] == "Step 7":
                sleep(0.1)
                print("<T1", flow[0] + ">", "COMMIT")
                break
        break

@transaction.atomic
def transaction2(flow):
    while True:
        while True:
            if flow[0] == "Step 3":
                sleep(0.1)
                print("<T2", flow[0] + ">", "BEGIN")
                flow[0] = "Step 4"
                break

        while True:
            if flow[0] == "Step 4":
                sleep(0.1)
                print("<T2", flow[0] + ">", "UPDATE")
                Person.objects.filter(id=2).update(name="Tom")
                flow[0] = "Step 5"
                break
        
        while True:
            if flow[0] == "Step 5":
                sleep(0.1)
                print("<T2", flow[0] + ">", "COMMIT")
                flow[0] = "Step 6"
                break
        break

def call_transcations(request): 
    flow = ["Step 1"]

    thread1 = Thread(target=transaction1, args=(flow,), daemon=True)
    thread2 = Thread(target=transaction2, args=(flow,), daemon=True)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    return HttpResponse("Call_transcations")

Однако, non-repeatable read произошел согласно результату, показанному на консоли, несмотря на то, что я установил SERIALIZABLE уровень изоляции на 'OPTIONS' в settings.py. Таким образом, это все еще будет READ COMMITTED уровень изоляции , на котором происходит неповторяемое чтение :

<T1 Step 1> BEGIN
<T1 Step 2> SELECT
2 David # Here
<T2 Step 3> BEGIN
<T2 Step 4> UPDATE
<T2 Step 5> COMMIT
<T1 Step 6> SELECT
2 Tom # Here
<T1 Step 7> COMMIT

А также, я смог получить журналы SQL запросов PostgreSQL ниже:

[16408]: BEGIN
[16408]: SELECT "store_person"."id", "store_person"."name" 
         FROM "store_person" 
         WHERE "store_person"."id" = 2 
         LIMIT 21
[8276]: BEGIN
[8276]: UPDATE "store_person" 
        SET "name" = 'Tom' 
        WHERE "store_person"."id" = 2
[8276]: COMMIT
[16408]: SELECT "store_person"."id", "store_person"."name" 
         FROM "store_person" 
         WHERE "store_person"."id" = 2 
         LIMIT 21
[16408]: COMMIT

В этой таблице ниже показан поток и журналы SQL-запросов PostgreSQL выше:

Flow Transaction 1 (T1) Transaction 2 (T2) Explanation
Step 1 BEGIN; T1 starts.
Step 2 SELECT "store_person"."id", "store_person"."name" FROM "store_person" WHERE "store_person"."id" = 2 LIMIT 21;

2 David
T1 reads David.
Step 3 BEGIN; T2 starts.
Step 4 UPDATE "store_person" SET "name" = 'Tom' WHERE "store_person"."id" = 2; T2 updates David to Tom.
Step 5 COMMIT; T2 commits.
Step 6 SELECT "store_person"."id", "store_person"."name" FROM "store_person" WHERE "store_person"."id" = 2 LIMIT 21;

2 Tom
T1 reads Tom instead of David after T2 commits.

*Non-repeatable read occurs!!

Step 7 COMMIT; T1 commits.

На самом деле, когда я непосредственно устанавливаю SERIALIZABLE уровень изоляции с помощью psql, как показано ниже:

postgres=# ALTER DATABASE postgres SET DEFAULT_TRANSACTION_ISOLATION TO 'SERIALIZABLE';

Неповторяемое чтение не произошло в Django, как показано ниже:

<T1 Step 1> BEGIN
<T1 Step 2> SELECT
2 David # Here
<T2 Step 3> BEGIN
<T2 Step 4> UPDATE
<T2 Step 5> COMMIT
<T1 Step 6> SELECT
2 David # Here
<T1 Step 7> COMMIT

Кроме того, имели место фантомное чтение, потерянное обновление и перекос записи.

Мои вопросы:

  1. Есть ли проблемы в Django?
  2. Есть ли другие простые способы установить уровень изоляции в Django?
Вернуться на верх