django操作mysql常见错误大全

因为我的机器使用的是mysql容器,所以可以打印环境环境获取登录账密

bash 复制代码
docker exec -it db printenv | grep MYSQL

下面用「Django + MySQL」的视角,把 开发/上线 99% 会踩的 MySQL 典型错误 汇总成一张"踩坑地图"。

每个错误都给出:

  1. 异常堆栈(Django 真实报错)
  2. 根因一句话
  3. 复现代码(最小 Django 示例)
  4. 修复方案(含 ORM 写法或配置)

复制即可复现,跟着敲一遍,以后看到同样日志秒定位。


0. 环境统一

  • Django 4.2 + mysqlclient 2.2 + MySQL 8.0
  • 默认配置(不改 SQL_MODE)以便暴露问题
python 复制代码
# settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "django_err",
        "USER": "root",
        "PASSWORD": "password",
        "HOST": "127.0.0.1",
        "PORT": "3306",
        "OPTIONS": {"init_command": "SET sql_mode='STRICT_TRANS_TABLES'"},  # 严格模式先打开
    }
}

1. Duplicate entry ------ 主键/唯一键冲突

异常

django 复制代码
django.db.utils.IntegrityError: (1062, "Duplicate entry 'tom' for key 'users.username'")

复现

python 复制代码
class User(models.Model):
    username = models.CharField(max_length=50, unique=True)

User.objects.create(username="tom")
User.objects.create(username="tom")  # 再敲一次

修复

python 复制代码
# 代码层先查后插 或 数据库层 on conflict
user, created = User.objects.get_or_create(username="tom")

2. Data too long ------ 列长度超限

异常

django 复制代码
django.db.utils.DataError: (1406, "Data too long for column 'title' at row 1")

复现

python 复制代码
class Article(models.Model):
    title = models.CharField(max_length=10)

Article.objects.create(title="12345678901")  # 11 个字符

修复

python 复制代码
# 要么改模型
title = models.CharField(max_length=255)
# 要么截断
Article.objects.create(title=long_title[:10])

3. DoesNotExist ------ 查询为空抛异常

异常

django 复制代码
django.core.exceptions.ObjectDoesNotExist: User matching query does not exist.

复现

python 复制代码
user = User.objects.get(pk=999)  # 没有这条记录

修复

python 复制代码
# 用 filter + first 或 get_object_or_404
user = User.objects.filter(pk=999).first()  # 返回 None
from django.shortcuts import get_object_or_404
user = get_object_or_404(User, pk=999)

4. Field cannot be null ------ 非空约束

异常

django 复制代码
django.db.utils.IntegrityError: (1048, "Column 'email' cannot be null")

复现

python 复制代码
class User(models.Model):
    email = models.EmailField()  # 默认 blank=False, null=False

User.objects.create(username="tom")  # 没给 email

修复

python 复制代码
# 1. 允许空
email = models.EmailField(blank=True, null=True)
# 2. 给默认值
email = models.EmailField(default="")
# 3. 代码里传值
User.objects.create(username="tom", email="tom@example.com")

5. Incorrect string value ------ 表情符/生僻字乱码

异常

django 复制代码
django.db.utils.OperationalError: (1366, "Incorrect string value: '\\xF0\\x9F\\x98\\x80...' for column 'nickname'")

复现

python 复制代码
User.objects.create(nickname="😀")  # utf8mb3 存不进 emoji

修复

  1. 数据库/表/列字符集改成 utf8mb4
sql 复制代码
ALTER DATABASE django_err CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. 连接层也指定:
python 复制代码
"OPTIONS": {"charset": "utf8mb4"},

再插入 emoji 就正常了。


6. Lost connection ------ 长查询被 kill

异常

django 复制代码
django.db.utils.OperationalError: (2013, 'Lost connection to MySQL server during query')

复现

python 复制代码
# 故意搞个大表全表扫 + 不睡觉
User.objects.all().select_related("profile")[0:100000]  # 100 万次 join

修复

  • 优化 SQL(加索引、分页、只取所需列)
  • 调大 wait_timeout / interactive_timeout(治标不治本)
  • iterator() 分批拉:
python 复制代码
for user in User.objects.all().iterator(chunk_size=2000):
    ...

7. Too many connections ------ 连接打满

异常

django 复制代码
django.db.utils.OperationalError: (1040, 'Too many connections')

复现

并发压测 ab -n 10000 -c 200 ... 超过 max_connections=151 即可。

修复

  1. 数据库层:温和涨上限
sql 复制代码
SET GLOBAL max_connections = 300;
  1. 应用层:用连接池 + 合理并发
python 复制代码
# settings.py 里加
DATABASES["default"]["CONN_MAX_AGE"] = 600  # 复用连接
  1. 代码里别泄露连接(长时间不 close)

8. Deadlock found ------ 并发死锁

异常

django 复制代码
django.db.utils.OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction')

复现

python 复制代码
# 两个 view 同时
@transaction.atomic
def debit(request):
    a = Account.objects.select_for_update().get(id=1)
    b = Account.objects.select_for_update().get(id=2)
    ...

# 另一个线程反向顺序
@transaction.atomic
def debit2(request):
    b = Account.objects.select_for_update().get(id=2)  # 先 2
    a = Account.objects.select_for_update().get(id=1)  # 后 1

交叉拿锁 → 死锁。

修复

  • 固定加锁顺序(总是 1→2)
  • 精简事务范围,尽快提交
  • 捕获重试(Django 3.2+ 自动重试 max_retries=3

9. IntegrityError ------ 外键级联失败

异常

django 复制代码
django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails ...)

复现

python 复制代码
class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)

Order.objects.create(user_id=9999)  # 不存在 user 9999

修复

python 复制代码
# 保证外键值存在
user = User.objects.get(pk=user_id)
Order.objects.create(user=user)

10. ProgrammingError ------ 拼错 raw SQL

异常

django 复制代码
django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual ...")

复现

python 复制代码
from django.db import connection
with connection.cursor() as c:
    c.execute("SELCT * FROM users WHERE id = %s", [1])  # SELCT 拼错

修复

  • 用 ORM 先顶一波,必须 raw 时开 sql_mode=STRICT 并打印语句再执行。

一键速查表(打印贴墙)

错误码 Django 异常 典型场景 最快修复
1062 IntegrityError 唯一键冲突 get_or_create
1406 DataError 列太长 加长/截断
1048 IntegrityError 非空未给 设默认值
1366 OperationalError emoji 乱码 utf8mb4
2013 OperationalError 长查询 索引+分页
1040 OperationalError 连接打满 连接池+涨上限
1213 OperationalError 死锁 固定顺序+重试

结语

把上面 10 个案例挨个 python manage.py shell 跑一遍,再遇到一样日志就能秒定位。

建议收藏 + 星标,下次面试/上线/救火,直接翻表。

相关推荐
身如柳絮随风扬2 小时前
MySQL核心知识
数据库·mysql
551只玄猫3 小时前
【数据库原理 实验报告1】创建和管理数据库
数据库·sql·学习·mysql·课程设计·实验报告·数据库原理
q5431470873 小时前
MySQL SQL100道基础练习题
数据库·mysql
zhoupenghui1684 小时前
mysql 中如果条件where中有or,则要求or两边的字段都必须有索引,否则不能用到索引, 为什么?
数据库·mysql·索引
eggwyw5 小时前
完美解决phpstudy安装后mysql无法启动
数据库·mysql
java修仙传5 小时前
MySQL 事务隔离级别详解
数据库·mysql·oracle
Irissgwe5 小时前
MySQL存储过程和触发器专题
数据库·mysql·oracle
skiy8 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
创世宇图8 小时前
Alibaba Cloud Linux 安装生产环境-mysql
linux·mysql
重庆小透明9 小时前
【搞定面试之mysql】第一篇:mysql的优化和索引
mysql·面试·职场和发展