Django/PostgreSQL事务隔离级别设置失效问题求助
解决Django+PostgreSQL设置Serializable事务隔离级别的问题
我看到你尝试把事务隔离级别设为最严格的Serializable,但配置后始终停留在Read Committed,并发测试也没达到预期效果。咱们一步步拆解问题并解决:
核心问题分析
你的配置存在两个关键错误:
- OPTIONS位置错误:你把
OPTIONS和default数据库配置平级放置,但Django要求OPTIONS必须嵌套在具体的数据库(比如default)配置内部,导致原有配置完全没被读取。 - Heroku配置覆盖丢失:当部署到Heroku时,
dj_database_url.config()会完全替换DATABASES['default']的内容,你之前设置的OPTIONS被彻底覆盖了。
修改后的正确配置
把OPTIONS放到default配置内部,并且在Heroku生成配置后重新注入隔离级别设置:
import psycopg2.extensions import os from django.conf import settings DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(settings.BASE_DIR, 'db.sqlite3'), # 将OPTIONS嵌套进default配置内 'OPTIONS': { 'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE, } } } if on_heroku: # 先获取Heroku的数据库配置 DATABASES['default'] = dj_database_url.config() # 为Heroku配置添加隔离级别OPTIONS DATABASES['default']['OPTIONS'] = { 'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE, }
正确验证隔离级别
你当前查询的default_transaction_isolation是数据库全局默认值,不是当前事务的实际隔离级别。应该查询当前连接/事务的级别:
@require_http_methods(["POST"]) @transaction.atomic @login_required() def api_test_add_one(request): cursor = connection.cursor() # 查询当前事务的实际隔离级别 cursor.execute('SHOW transaction_isolation') logger.info("当前事务隔离级别: " + str(cursor.fetchone())) # 也可以直接通过Django连接对象获取 logger.info("Django连接隔离级别: " + str(connection.isolation_level)) return HttpResponse("{}", content_type="application/json")
并发测试的注意事项
Serializable级别会通过检测事务间的写冲突来阻止幻读,当冲突发生时PostgreSQL会自动回滚其中一个事务并抛出TransactionRollbackError。Django的@transaction.atomic默认会自动重试事务(最多5次),你可以观察日志中的重试记录,或者在代码中捕获该异常做自定义处理。
内容的提问来源于stack exchange,提问作者Patrik Beck
相关产品推荐
相关产品推荐

