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 跑一遍,再遇到一样日志就能秒定位。

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

相关推荐
千层冷面12 小时前
数据库分库分表
java·数据库·mysql·oracle
清风拂山岗 明月照大江14 小时前
MySQL运维
运维·数据库·mysql
进击的CJR14 小时前
redis哨兵实现主从自动切换
mysql·ffmpeg·dba
crossaspeed14 小时前
MySql三大日志——(八股)
数据库·mysql
墨香幽梦客17 小时前
数据库选型对比:MySQL、Oracle与PostgreSQL的企业应用场景分析
数据库·mysql·oracle
清风拂山岗 明月照大江18 小时前
MySQL进阶
数据库·sql·mysql
YIN_尹18 小时前
【MySQL】表的约束(上)
android·数据库·mysql
云和数据.ChenGuang19 小时前
运维故障之MySQL 连接授权错误
运维·数据库·人工智能·mysql
Maggie_ssss_supp19 小时前
Linux-MySQL数据类型&表操作
数据库·mysql
廋到被风吹走19 小时前
【数据库】【MySQL】高可用架构深度解析:从主从复制到自动切换
数据库·mysql·架构