fix: set default mysql isolation level to 'READ COMMITTED' (#30174)

Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
This commit is contained in:
Maxime Beauchemin 2024-09-09 17:00:54 -07:00 committed by GitHub
parent fed117fbf7
commit 6baeb659a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 34 additions and 12 deletions

1
.gitattributes vendored
View File

@ -1 +1,2 @@
docker/**/*.sh text eol=lf
*.svg binary

View File

@ -196,12 +196,14 @@ SQLALCHEMY_DATABASE_URI = (
# SQLALCHEMY_DATABASE_URI = 'mysql://myapp@localhost/myapp'
# SQLALCHEMY_DATABASE_URI = 'postgresql://root:password@localhost/myapp'
# The default MySQL isolation level is REPEATABLE READ whereas the default PostgreSQL
# isolation level is READ COMMITTED. All backends should use READ COMMITTED (or similar)
# to help ensure consistent behavior.
SQLALCHEMY_ENGINE_OPTIONS = {
"isolation_level": "SERIALIZABLE", # SQLite does not support READ COMMITTED.
}
# This config is exposed through flask-sqlalchemy, and can be used to set your metadata
# database connection settings. You can use this to set arbitrary connection settings
# that may be specific to the database engine you are using.
# Note that you can use this to set the isolation level of your database, as in
# `SQLALCHEMY_ENGINE_OPTIONS = {"isolation_level": "READ COMMITTED"}`
# Also note that we recommend READ COMMITTED for regular operation.
# Find out more here https://flask-sqlalchemy.palletsprojects.com/en/3.1.x/config/
SQLALCHEMY_ENGINE_OPTIONS = {}
# In order to hook up a custom password store for all SQLALCHEMY connections
# implement a function that takes a single argument of type 'sqla.engine.url',

View File

@ -32,6 +32,7 @@ from flask_session import Session
from werkzeug.middleware.proxy_fix import ProxyFix
from superset.constants import CHANGE_ME_SECRET_KEY
from superset.databases.utils import make_url_safe
from superset.extensions import (
_event_logger,
APP_DIR,
@ -482,12 +483,36 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods
self.configure_wtf()
self.configure_middlewares()
self.configure_cache()
self.set_db_default_isolation()
with self.superset_app.app_context():
self.init_app_in_ctx()
self.post_init()
def set_db_default_isolation(self) -> None:
# This block sets the default isolation level for mysql to READ COMMITTED if not
# specified in the config. You can set your isolation in the config by using
# SQLALCHEMY_ENGINE_OPTIONS
eng_options = self.config["SQLALCHEMY_ENGINE_OPTIONS"] or {}
isolation_level = eng_options.get("isolation_level")
set_isolation_level_to = None
if not isolation_level:
backend = make_url_safe(
self.config["SQLALCHEMY_DATABASE_URI"]
).get_backend_name()
if backend in ("mysql", "postgresql"):
set_isolation_level_to = "READ COMMITTED"
if set_isolation_level_to:
logger.info(
"Setting database isolation level to %s",
set_isolation_level_to,
)
with self.superset_app.app_context():
db.engine.execution_options(isolation_level=set_isolation_level_to)
def configure_auth_provider(self) -> None:
machine_auth_provider_factory.init_app(self.superset_app)

View File

@ -59,9 +59,6 @@ if make_url(SQLALCHEMY_DATABASE_URI).get_backend_name() == "sqlite":
"removed in a future version of Superset."
)
if make_url(SQLALCHEMY_DATABASE_URI).get_backend_name() in ("postgresql", "mysql"):
SQLALCHEMY_ENGINE_OPTIONS["isolation_level"] = "READ COMMITTED" # noqa: F405
# Speeding up the tests.integration_tests.
PRESTO_POLL_INTERVAL = 0.1
HIVE_POLL_INTERVAL = 0.1

View File

@ -41,9 +41,6 @@ if make_url(SQLALCHEMY_DATABASE_URI).get_backend_name() == "sqlite":
in a future version of Superset."
)
if make_url(SQLALCHEMY_DATABASE_URI).get_backend_name() in ("postgresql", "mysql"):
SQLALCHEMY_ENGINE_OPTIONS["isolation_level"] = "READ COMMITTED" # noqa: F405
SQL_SELECT_AS_CTA = True
SQL_MAX_ROW = 666