Уровень изоляции не меняется, даже если установить "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
Кроме того, имели место фантомное чтение, потерянное обновление и перекос записи.
Мои вопросы:
- Есть ли проблемы в Django?
- Есть ли другие простые способы установить уровень изоляции в Django?