Changing MySQL isolation level on Django/Elastic beanstalk/RDS
Question:
I’m trying to change the isolation level of my MySQL instance on RDS through a Django application.
I’ve followed the recommendation here
So, I changed my Django db settings to:
'OPTIONS': {
'init_command': 'SET default_storage_engine=INNODB; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED'
}
This command works fine when I run directly in the database (MySQL version 8.0.13)
However, when I try to deploy it to Elastic Beanstalk I got the following error:
Command failed on instance. Return code: 1 Output: (TRUNCATED)... manual that corresponds to your MySQL server version for the right syntax to use near 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED' at line 1")
I also tried changing the line to:
SET default_storage_engine=INNODB, SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
With the same results
Any idea what might be wrong? Or another solution that I can use (maybe I can just run this command and set it to global isolation level instead?)
Answers:
Perhaps that OPTIONS
cannot handle 2 commands. So remove the first one — it is useful only when creating a new table. And it may be possible to specify the ENGINE=InnoDB
on any CREATE TABLEs
you need to do. Anyway, I would expect AWS to default to that. And 8.0 has that engine default.
Can you try like below, anyone should work.
SET @@SESSION.transaction_isolation = value;
SET SESSION transaction_isolation = value;
SET transaction_isolation = value;
For MySQL, you will be able to set and check READ COMMITTED
by running the raw queries after database settings in settings.py
as shown below. *If running the raw query before database settings, error occurs:
# "settings.py"
from django.db import connection
# ...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'DB_NAME',
'USER': 'DB_USER',
'PASSWORD': 'DB_PASSWORD',
'HOST': 'localhost',
'PORT': '3306',
}
}
# ↓ ↓ ↓ Set isolation level ↓ ↓ ↓
cursor = connection.cursor()
query = """
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
"""
cursor.execute(query)
# ↓ ↓ ↓ Check isolation level ↓ ↓ ↓
cursor.execute('SELECT @@GLOBAL.transaction_isolation;')
print(cursor.fetchone()) # ('read committed',)
*settings.py
is run every time Django Server is run with the command below or every time Django Server is reloaded by writing code so transaction is set every time Django Server is run with the command below or every time Django Server is reloaded by writing code:
python manage.py runserver 0.0.0.0:8000
For me with PostgreSQL, "init_command": ...
and "isolation_level"
in "OPTIONS": {}
below didn’t work so I couldn’t set SERIALIZABLE
in settings.py
:
# "settings.py"
"OPTIONS": {
"init_command": "ALTER DATABASE postgres SET DEFAULT_TRANSACTION_ISOLATION TO 'SERIALIZABLE';"
"isolation_level": psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
}
I’m trying to change the isolation level of my MySQL instance on RDS through a Django application.
I’ve followed the recommendation here
So, I changed my Django db settings to:
'OPTIONS': {
'init_command': 'SET default_storage_engine=INNODB; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED'
}
This command works fine when I run directly in the database (MySQL version 8.0.13)
However, when I try to deploy it to Elastic Beanstalk I got the following error:
Command failed on instance. Return code: 1 Output: (TRUNCATED)... manual that corresponds to your MySQL server version for the right syntax to use near 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED' at line 1")
I also tried changing the line to:
SET default_storage_engine=INNODB, SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
With the same results
Any idea what might be wrong? Or another solution that I can use (maybe I can just run this command and set it to global isolation level instead?)
Perhaps that OPTIONS
cannot handle 2 commands. So remove the first one — it is useful only when creating a new table. And it may be possible to specify the ENGINE=InnoDB
on any CREATE TABLEs
you need to do. Anyway, I would expect AWS to default to that. And 8.0 has that engine default.
Can you try like below, anyone should work.
SET @@SESSION.transaction_isolation = value;
SET SESSION transaction_isolation = value;
SET transaction_isolation = value;
For MySQL, you will be able to set and check READ COMMITTED
by running the raw queries after database settings in settings.py
as shown below. *If running the raw query before database settings, error occurs:
# "settings.py"
from django.db import connection
# ...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'DB_NAME',
'USER': 'DB_USER',
'PASSWORD': 'DB_PASSWORD',
'HOST': 'localhost',
'PORT': '3306',
}
}
# ↓ ↓ ↓ Set isolation level ↓ ↓ ↓
cursor = connection.cursor()
query = """
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
"""
cursor.execute(query)
# ↓ ↓ ↓ Check isolation level ↓ ↓ ↓
cursor.execute('SELECT @@GLOBAL.transaction_isolation;')
print(cursor.fetchone()) # ('read committed',)
*settings.py
is run every time Django Server is run with the command below or every time Django Server is reloaded by writing code so transaction is set every time Django Server is run with the command below or every time Django Server is reloaded by writing code:
python manage.py runserver 0.0.0.0:8000
For me with PostgreSQL, "init_command": ...
and "isolation_level"
in "OPTIONS": {}
below didn’t work so I couldn’t set SERIALIZABLE
in settings.py
:
# "settings.py"
"OPTIONS": {
"init_command": "ALTER DATABASE postgres SET DEFAULT_TRANSACTION_ISOLATION TO 'SERIALIZABLE';"
"isolation_level": psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
}