惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
Jina AI
Jina AI
博客园 - 司徒正美
雷峰网
雷峰网
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园_首页
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
I
InfoQ
博客园 - Franky
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
Cyberwarzone
Cyberwarzone
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
Threatpost
Cloudbric
Cloudbric
D
Docker
M
MIT News - Artificial intelligence
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Vercel News
Vercel News
Martin Fowler
Martin Fowler
J
Java Code Geeks
AWS News Blog
AWS News Blog
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
L
Lohrmann on Cybersecurity
Hacker News: Ask HN
Hacker News: Ask HN
Last Week in AI
Last Week in AI
S
Security @ Cisco Blogs
Help Net Security
Help Net Security
C
Cisco Blogs
V
V2EX
博客园 - 【当耐特】
I
Intezer
爱范儿
爱范儿
F
Fortinet All Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Privacy International News Feed
IT之家
IT之家
L
LINUX DO - 最新话题
B
Blog RSS Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

追梦人物的博客

0x05:Merkle Tree & Patricia Trie 0x04:ECDSA - 以太坊设计与实现 LeetCode 105 从前序与中序遍历构造二叉树 迭代算法原理 + 完整证明 0x03:Address - 以太坊设计与实现 0x02:Secp256k1 - 以太坊设计与实现 0x00:专栏开篇 - 以太坊设计与实现 0x01:RLP 编码 - 以太坊设计与实现 Bellman-Ford 算法原理及其在 DeFi 套利中的应用 - 追梦人物的博客 迪杰斯特拉(Dijkstra)最短路径算法原理、实现与证明 - 追梦人物的博客 实战:CEX-DEX 稳定币套利监控程序开发 - 追梦人物的博客 CEX-DEX 稳定币套利模型 - 追梦人物的博客 Uniswap 手续费和协议费机制剖析 - 追梦人物的博客 Uniswap 流动性机制及相关数学原理分析 - 追梦人物的博客 uv 替代 pyenv + pipx + poetry 环境管理实践 Rust 项目从创建到发布 - 追梦人物的博客 VS Code 调试 Python - 追梦人物的博客 比特币跨市场套利的数学模型 - 追梦人物的博客 ERC-20 相关知识点总结 - 追梦人物的博客 自动生成接口文档 - HelloDjango - django REST framework 教程 单元测试 - HelloDjango - django REST framework 教程 限制接口访问频率 - HelloDjango - django REST framework 教程 API 版本管理 - HelloDjango - django REST framework 教程 如何在 Windows 下搭建高效的 django 开发环境 拓展Python Markdown - 追梦人物的博客 加缓存为接口提速 - HelloDjango - django REST framework 教程 基于 drf-haystack 实现文章搜索接口 - HelloDjango 评论接口 - HelloDjango - django REST framework 教程 实现分类、标签、归档日期接口 - HelloDjango - django REST framework 教程 在接口返回Markdown解析后的内容 - HelloDjango - django REST framework 教程 文章详情接口 - HelloDjango - django REST framework 教程 分页 - HelloDjango - django REST framework 教程 使用视图集简化代码 - HelloDjango - django REST framework 教程 用类视图实现首页 API - HelloDjango - django REST framework 教程 实现博客首页文章列表 API - HelloDjango - django REST framework 教程 初始化 RESTful API 风格的博客系统 - HelloDjango django-rest-framework 是什么鬼? - HelloDjango - django REST framework 教程 结束 or 开始? - HelloDjango Coverage.py 统计测试覆盖率 - HelloDjango - Django博客教程(第二版) 单元测试:测试评论应用 - HelloDjango - Django博客教程(第二版) 单元测试:测试 blog 应用 - HelloDjango Django Haystack 全文检索与关键词高亮 - HelloDjango Django 博客实现简单的全文搜索 - HelloDjango - Django博客教程(第二版) 开启 Django 博客的 RSS 功能 - HelloDjango 统计各个分类和标签下的文章数 - HelloDjango - Django博客教程(第二版) 稳定易用的 Django 分页库,完善分页功能 - HelloDjango 通过 Django Pagination 实现简单分页 - HelloDjango 在脚本中使用 ORM:Faker 批量生成测试数据 - HelloDjango Django 官方推荐的姿势:类视图 - HelloDjango - Django博客教程(第二版) Django 使用 union 合并不同模型(Model) 的查询集(QuerySet) 开发博客文章阅读量统计功能 - HelloDjango - Django博客教程(第二版) 使用 Docker 让部署 Django 项目更加轻松 - HelloDjango 使用 Certbot 向 Let's Encrypt 免费申请 HTTPS 证书 - HelloDjango 使用 Fabric 自动化部署 - HelloDjango 博客代码开源啦 - 追梦人物的博客 (赠书)推荐一本django书籍:Django企业开发实战 - 追梦人物的博客 Nginx+Gunicorn+Supervisor 部署 Django 博客应用 - HelloDjango 优化博客功能细节,提升使用体验 - HelloDjango - Django博客教程(第二版) 交流的桥梁:评论功能 - HelloDjango - Django博客教程(第二版) 分类、归档和标签页 - HelloDjango - Django博客教程(第二版) 页面侧边栏:使用自定义模板标签 - HelloDjango - Django博客教程(第二版) 自动生成文章摘要 - HelloDjango - Django博客教程(第二版) Markdown 文章自动生成目录,提升阅读体验 - HelloDjango - Django博客教程(第二版) 让博客支持 Markdown 语法和代码高亮 - HelloDjango 开发博客文章详情页 - HelloDjango - Django博客教程(第二版) 创作后台开启,请开始你的表演 - HelloDjango - Django博客教程(第二版) 博客从“裸奔”到“有皮肤” - HelloDjango - Django博客教程(第二版) Django 的接客之道 - HelloDjango - Django博客教程(第二版) Django 迁移、操作数据库 - HelloDjango - Django博客教程(第二版) 创建 Django 博客的数据库模型 - HelloDjango 开始进入 django 开发之旅 - HelloDjango "空空如也"的博客应用 - HelloDjango - Django博客教程(第二版) 一种自顶而下的Python装饰器设计方法 - 追梦人物的博客 Python提取支付宝和微信支付二维码 - 追梦人物的博客 2018 - 我的学生生涯最后一年回顾 - 追梦人物的博客 批量清除todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 筛选练习参考答案 - Vue 2.x Todo 教程练习参考答案 删除todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 编辑todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 添加todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 标为完成练习参考答案 - Vue 2.x Todo 教程练习参考答案 入门仪式_Hello_Vue练习参考答案 - Vue 2.x Todo 教程练习参考答案 组件化todo应用 - Vue 2.x Todo 教程 批量清除todo - Vue 2.x Todo 教程 本地存储 - Vue 2.x Todo 教程 筛选 - Vue 2.x Todo 教程 还剩多少todo未完成 - Vue 2.x Todo 教程 自定义指令实现自动聚焦 - Vue 2.x Todo 教程 全部标为完成 - Vue 2.x Todo 教程 删除todo - Vue 2.x Todo 教程 编辑todo - Vue 2.x Todo 教程 添加todo - Vue 2.x Todo 教程 标为完成 - Vue 2.x Todo 教程 UI - Vue 2.x Todo 教程 显示todo列表 - Vue 2.x Todo 教程 入门仪式:Hello Vue - Vue 2.x Todo 教程 在学习django-rest-framework时收集的学习资料推荐 - 追梦人物的博客 区块链理论与应用研究小组成员招募书 - 追梦人物的博客 Python界网红,豆瓣工程师董伟明加了我的QQ后 - 追梦人物的博客 招募Django学习小组项目组核心成员 - 追梦人物的博客
Django 老项目如何从 SQLite 迁到 PostgreSQL
2020-10-04 · via 追梦人物的博客

因为 Django 项目配置 SQLite 非常简单,而且考虑到个人博客访问量不会很大,所以线上环境直接使用了 SQLite 数据库。

博客上线初期一切运行良好,直到最近频繁收到 database is locked 的异常告警。经过一番调研,大致确定了导致异常的原因:并发情况下,如果线程等待数据库锁的时间超过指定时间(默认为 5 秒)则会抛出 database is locked 异常。Stackoverflow 上有人问了类似的问题,解决方案大致可总结为这几种:

  1. 更换数据库引擎。
  2. 优化应用程序,减少并发。
  3. 增加锁超时时间。

方案 3 治标不治本,方案 2 比较麻烦,而且一直使用 SQLite 也不是长远之计,所以长痛不如短痛,决定线上环境彻底换掉 SQLite,投入 PostgreSQL 的怀抱。

数据迁移方案

一开始想到的方案是将 SQLite 中的数据导出为 SQL 语句,再导入 PostgreSQL 数据库中,但毕竟分属 2 个不同的数据库引擎,很容易出现不兼容的 SQL 语句,所以这个方案被否掉了。

最终决定采用的方案是将 SQLite 中的数据导出为 JSON 格式的数据,再导入的 PostgreSQL 数据库中,Django 提供了导出和导入的命令,实施起来非常方便。

以下是整个迁移流程:

  1. 导出 JSON 格式的数据:python manage.py dumpdata > db.json

  2. 修改 Django 项目的数据库引擎配置;

  3. 生成新的数据库表:python manage.py migrate

  4. 删除新表中自动生成的 ContentType 有关的数据:

$ python manage.py shell
>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.all().delete()
  1. 导入 JSON 数据:python manage.py loaddata db.json

第 4 步需要特别注意,新生成的数据库表,Django 会自动写入 ContentType 有关的数据,需要先删除掉,否则会和导入的数据的冲突。

遇到的坑

尽管迁移步骤非常的简单,但是也存在不少的坑,以下就是我遇到的一些坑和填坑方法。

坑1:不兼容的数据格式

SQLite 数据库字段的类型比较简单,而 PostgreSQL 字段类型更加丰富,有些能够存入 SQLite 的数据导入 PostgreSQL 时无法通过格式校验。

例如我的博客评论有一个 ip 字段,某些空记录的值为 b''。SQLite 中字段类型是 char,而 PostgreSQL 中是 inet,inet 施加的校验更强,值 b'' 无法通过校验,因此导入时会报错。

解决方案就是导出数据前,先将 ip 字段的值修改为和 PostgreSQL inet 字段类型兼容的值。

坑2:PostgreSQL 不允许 join 不同类型的字段

PostgreSQL 不同类型的字段不允许 join 操作。因此在 SQLite 和 MySQL 中执行没问题的 SQL 语句在 PostgreSQL 中就会报错。

没有太好的解决方案,只能把各个表中需要 join 的字段改为相同类型。如果无法修改,建议更换数据库为 MySQL。

坑3:当心应用程序自动生成的数据

应用程序很可能会有当某条记录存入数据库时,自动生成某些关联数据的逻辑,导入数据时就会产生冲突。

例如我的博客应用中,当 Users 表中存入一条用户记录后,就会在 token 表中生成一条关联的记录,那么导入数据时,原数据中的 token 就会和新生成的 token 冲突。

解决方案是,找出自动生成的数据,将他们从导出的数据中排除。dumpdata 命令支持指定排除的数据,例如:python manage.py dumpdata > db.json --exclude=authtoken 将排除 authtoken 应用中的数据。

总结

  1. 更换数据库引擎是一件异常痛苦的事,所以在项目初期就要选好数据库引擎,减少数据迁移的麻烦。
  2. 尽管 Django ORM 非常强大,在一定程度上提供了数据库引擎的抽象,但仍然无法避免在某个数据库工作良好的代码,换到另一个数据库就无法使用的情况,所以无论是开发、测试还是线上,尽量使用相同的数据库引擎。
  3. 这种数据迁移方式效率非常低,我博客 200M 的数据导入就花了 30 多分钟,如果数据量比较大,最好还是换一种更加高效的方式。

-- EOF --