问题来源

最近编写我的kook机器人的时候,发现MySQL对于这种低访问频次的应用并不友好,经常出现断连的问题,具体到python中的报错如下

1
pymysql.err.InterfaceError: (0, '')

出现这种报错,就可以认为是MySQL那端因为自身策略中断了和你的应用的链接。因为我的机器人和MySQL是在同一台主机上,肯定不是网络本身问题导致的。

所以我需要将MySQL数据库换成sqlite3数据库。

MySQL转sqlite3

导出MySQL中的数据

好在我的机器人使用的是python的peewee这个ORM库,只需要修改底层的DB引擎就能快速在MySQL和sqlite3之间切换。我们要解决的只是怎么把MySQL8.0.30的数据导入到sqlite3中。

本文测试使用的版本为:MySQL 8.0.30sqlite3 3.44.0

首先是从MySQL将数据库里面的所有数据导出为sql文件,因为我安装了1panel服务器面板,所以可以直接使用面板的备份功能,再把备份好的tar下载下来(里面就是sql文件)

这里给出用命令行来处理的方式,一般使用的工具为mysqldump,在安装MySQL的时候这个工具应该就会连带安装。我的MySQL是用docker安装的,docker容器内的终端也有这个命令工具。

1
2
3
4
5
6
7
[root@RainYun-8aNbbsmA:~/docker]# docker exec -it mysql /bin/bash
bash-4.4# mysqldump
Usage: mysqldump [OPTIONS] database [tables]
OR mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]
OR mysqldump [OPTIONS] --all-databases [OPTIONS]
For more options, use mysqldump --help
bash-4.4#

导出整个数据库的数据到sql的命令如下

1
mysqldump -u username -ppassword dbname > dbname.sql;

比如我有个testdb数据库,将其导入testdb.sql的命令如下,这里我直接使用了root用户来处理。

1
mysqldump -uroot -p123456 testdb > testdb.sql

因为在命令行使用密码被认为是不安全的,所以键入如上命令的时候会有一个警告,可以忽略它。

1
mysqldump: [Warning] Using a password on the command line interface can be insecure.

ls查看一下,当前路径上已经有我们需要的sql数据文件了。

docker内文件拷贝到宿主机

因为我现在的这个操作是在一个docker容器里面,我还需要将其从docker中拷贝出来,方法有两个

  1. 将sql文件拷贝到docker的持久化目录中(即映射到了宿主机的目录中);
  2. 使用docker copy命令;

对于1panel安装的MySQL容器而言,你可以在容器的详细设置里面看到映射路径的关系。

image.png

如果使用docker cp命令,格式如下

1
docker cp 容器ID:容器内路径 宿主机路径

这里的容器ID可以是容器的名字,也可以是docker ps命令查看到的容器CONTAINER ID;mysqldump命令弄出来的sql文件是在容器内的根目录上。

1
2
# docker cp mysql:/testdb.sql ~/testdb.sql
Successfully copied 9.85MB to /root/testdb.sql

修改sql文件

MySQL导出的sql文件不能直接被sqlite3识别,在我的机器人数据库中遇到如下几个问题,需要修改sql文件。

  • 用peewee创建sqlite数据库时生成的create table语句替换MySQL导出的sql文件内部已有的建表语句;
  • 删除sql文件中的LOCK TABLESUNLOCK TABLES;,因为sqlite不支持;
  • sql文件中的转义字符\"替换成"。因为在sqlite3中不需要进行此转义。如果不修改,那么在sqlite3中list的json字符串中就会留有\"导致无法被json.loads(猜测sqlite3中'的优先级高于"

首先是把python中peewee使用的数据库模型改成sqlite,然后启动一下这个机器人,此时peewee就会创建一个db文件。

1
sqlite3 数据库文件名.db

进入该db文件后执行如下查询命令,能看到sqlite3的建表语句,将其替换掉MySQL中导出sql里面的建表命令。

1
SELECT sql FROM sqlite_master WHERE type='table';

如果你用的不是peewee这种ORM库,则还需要自行修改建表命令为sqlite3的命令(可以问问gpt让他帮你改一下,或者自己重写一个)。比如在sqlite3中就不支持表后跟随的AUTO_INCREMENT=4728语句。

文件导入到sqlite3

sqlite3的导入命令格式如下,左侧是数据库文件名字,右侧是需要导入的源sql文件。为了避免文件名编码问题,建议使用全英文名字。

1
sqlite3 数据库名字.db < 需要导入的文件.sql

这个命令成功的时候不会有任何输出,使用如下命令进入导入后生成的db文件中

1
sqlite3 数据库名字.db

不出意外的话,所有数据就已经导入到这个新的数据库文件中了,检查一下和MySQL中的数据库有没有不一样的地方吧!

The end

有更多问题,欢迎评论留言讨论。