Django 部署准备之一SQLite迁移到MySQL

前言

Django开发的时候为了方面,内置了sqlite数据库,可以直接用,不用过多关心,直接ORM操作即可。

MysqlSqlite
特点为服务端设计轻量级,可嵌入手机应用
高并发不能
占用内存比SQLite
适用性服务器手机,桌面应用

等我们Django业务基本开发完了,部署之前,我们最好把SQLite迁移到Mysql,现在本地Mac电脑为例,操作一下迁移以及遇到的坑

安装

方式一(手动安装,不推荐)

- 下载地址:https://www.mysql.com/downloads/
- 滚动网页至最下方,选择`DOWNLOADS => MySQL  Community  Server`

跟着提示安装后需要配置环境变量
不配置环境变量的话,执行mysql命令,必须在mysql的安装目录下,所以选择配置环境变量。在终端中,进入到用户目录下,执行 vim .bash_profile 或者直接执行vim ~/.bash_profile ,按i进入编辑模式,添加如下内容,按esc,输入:wq退出并保存。

# mysql
export PATH=${PATH}:/usr/local/mysql/bin
#快速启动、结束MySQL服务, 可以使用alias命令
alias mysqlstart='sudo /usr/local/mysql/support-files/mysql.server start'
alias mysqlstop='sudo /usr/local/mysql/support-files/mysql.server stop'

我们就可以在任何地方执行mysql命令了。

  • 终端输入myqsl -u root -p启动MySQL,安装地址是/usr/local/mysql

方式二(Homebrew)

brew install mysql
# brew uninstall mysql
# brew list
mysql -V
mysql  Ver 8.0.18 for osx10.14 on x86_64 (Homebrew)

以上安装成功默认是没有密码的,MySQL 8以上新增了安全配置引导,下面有介绍,如果不想设置密码,可以直接进入

mysql -u root -p
直接回车即可

MySQL 密码安全设置

MySQL 8新增了安全设置向导,对于在服务器部署MySQL来说,简化了安全设置的操作。

  1. 密码强度验证插件
  2. 修改root账号密码
  3. 移除匿名用户
  4. 禁用root账户远程登录
  5. 移除测试数据库(test)
  6. 重新加载授权表
  • 示例
/usr/local/opt/mysql/bin/mysql_secure_installation # mysql 提供的配置向导

Securing the MySQL server deployment.

Enter password for user root:

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: no
#这里我选了不安全密码强度验证插件

Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : no
#这里我选了不修改root密码
 ... skipping.
 
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : yes
Success.
#这里我选择了移除匿名用户


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : yes
Success.
#这里我选择了禁用root账号远程登录访问

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : no
 ... skipping.
 #这里我选择了不移除测试数据库
 
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : yes
Success.
#这里我选择了重新加载权限表,因为我前面选择了禁用root账号远程登录访问

All done!

MySQL忘记了Root密码操作(em…这个真的很重要)

MySQL官网链接忘记密码操作
这里看下除了Window的其他系统如何操作。
1.如果有不要,请先停止MySQL相关服务。

ps -ef | grep mysql

1118089483  2247     1   0  3:12下午 ttys000    0:00.02 /bin/sh /usr/local/Cellar/mysql/8.0.18/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/FVFXGM44HV29.pid
1118089483  2358  2247   0  3:12下午 ttys000    0:04.24 /usr/local/Cellar/mysql/8.0.18/bin/mysqld --basedir=/usr/local/Cellar/mysql/8.0.18 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/Cellar/mysql/8.0.18/lib/plugin --log-error=FVFXGM44HV29.err --pid-file=/usr/local/var/mysql/FVFXGM44HV29.pid
1118089483  2522  2154   0  3:24下午 ttys000    0:00.01 grep mysql

如果有相关进程,需要关闭
mysql.service stop

# kill pid 

2.--skip-grant-tables启动
该方法重启,任何人都无需密码就可以使所有的权限,因此,我们会跟上--skip-networking阻止远程链接

/usr/local/bin/mysqld --skip-grant-tables --skip-networking &

3.修改密码
这里直接alter是会报错的,需要先刷新权限

mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
mysql> show columns from user; # 查看列  desc 表名;
mysql> select host, user, authentication_string from user;  # 查看信息

4.这里的密码默认都是高强度的,别入你之前通过安全设置设置过,你可以修改对应的全局密码管理设置

mysql> show variables like 'validate_password%';
+--------------------------------------+--------+
| Variable_name                        | Value  |
+--------------------------------------+--------+
| validate_password.check_user_name    | ON     |
| validate_password.dictionary_file    |        |
| validate_password.length             | 8      |
| validate_password.mixed_case_count   | 1      |
| validate_password.number_count       | 1      |
| validate_password.policy             | MEDIUM |
| validate_password.special_char_count | 1      |
+--------------------------------------+--------+
7 rows in set (0.00 sec)

mysql> 

这里看到倒数第二条是MEDIUM,我们需要改成LOW,修改密码强度

SET GLOBAL validate_password.policy=LOW;

然后修改密码位数

SET GLOBAL validate_password.length=6;

现在可以为MySQL设置简单密码了,只要满足六位的长度即可,

ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';

重启

mysql.server restart
#也可以使用命令:brew services restart mysql
#不过建议使用命令:mysql.server restart在出错时可以看到更准确完整的信息

建表

我们开发时用的SQLite数据库,在生产部署之前都要把本地的数据表迁移到MySQL去。由于MySQL的密码强度问题,经常忘记密码的同学直接去上面的知识点操作一下。下面开始建数据库,准备配置到Django的setting.py中去。

ps -ef | grep mysql
# 没启动就启动
mysql.service start
# 进入
mysql -u root -p
# 查看
show databases;
# 开始创建
create database mikejingsitedb charset=utf8mb4 default collate utf8mb4_unicode_ci;

看到这里有些小伙伴会觉得有点不对啊,一般的操作是create database xxx charset=utf8,这里花里胡哨的操作的参数,下面介绍下

collate和charset用法

default collate utf8mb4_unicode_ci; 介绍collate之前先说个题外话,大家应该都很熟悉,mysql中utf8和utf8mb4两种编码,可以这么说吧,大家可以忘记这个utf8这个东西,永远使用utf8mb4,这是MySQL的遗留问题,utf8最多支持3bytes字节长度的字符编码,对于一些需要占据4个字节的文字,比如emoji表情,mylsqutf8就不支持了,要使用utf8mb4才行。

所谓collate utf8mb4_unicode_ci,通俗的翻译为校验通过utf8超集,utf8mb4(utf8 mobile 4bytes)的unicode编码,而且是case insensitive(忽略大小写,还有个缩写是cs=case sensitive,顾名思义开始需要比较大小写)。对于MySQL中那些类型字段,如VARCHAR,CHAR,TEXT类型的列,都需要一个COLLATE类型来告诉他们排序的规则。简而言之,COLLATE会影响到ORDER BY语句的顺序,会影响到WHERE条件中大于小于号筛选出来的结果,会影响DISTINCTGROUP BYHAVING语句的查询结果。凡是涉及到排序,比较的地方,都会和COLLATE有关。

详细的介绍可以查看这个文章

MySQL字符编码

有了上面的介绍,我们就需要在my.cnf(Mac) my.ini(Windows)进行字符集配置。
默认字符集使用utf8mb4版本

#修改配置文件
vim /usr/local/etc/my.cnf

[mysqld]
...
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4

character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
  • 重启查看
mysql.server restart
#也可以使用命令:brew services restart mysql
#不过建议使用命令:mysql.server restart在出错时可以看到更准确完整的信息

MySQL不同版本加密方式兼容

1.配置文件修改
MySQL 8.0默认是cacheing_sha2_password 5.7和5.6是mysql_native_password,为了兼容设置如下把默认加密方式改成default_authentication_plugin = mysql_native_password

新版本如果你用Navicat去链接,就会报错

2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found

编辑vim /usr/local/etc/my.cnf插入一条数据
default_authentication_plugin=mysql_native_password
上面的这种方案对已有的账户是无法修改的,只是后续新增的账户就会默认的Plugin变成mysql_native_password
在这里插入图片描述
2.sql修改

ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #修改加密规则 
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; #更新一下用户的密码 
FLUSH PRIVILEGES; #刷新权限

因此,后面授权新用户的方式可以在后面跟一个加密方式,默认是跟着配置文件走

create user 'root'@'localhost' identified WITH mysql_native_password BY 'password';
grant all privileges on *.* to root@'localhost' with grant option;
flush privileges;

时区问题(后面启动博客就能遇到)

这里先把数据库的时区问题解决了
macOS。这些文件的一个可能位置是/usr/share/zoneinfo 目录 导入mysql数据时区

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p

导入后可以通过下面两个方式查看时区是否正确

select timediff(now(),convert_tz(now(),@@session.time_zone,'+00:00')); 
SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP); 

# 如果是中国标准时间, 会输出08:00

配置Django的数据库为MySQL

create database mikejingsitedb charset=utf8mb4 default collate utf8mb4_unicode_ci;
1.上面已经创建好了数据库,开始配置settings.py

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
# mikejingsitedb    mkjkejingsitedb2
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # 后端数据库引擎
        'NAME': 'mkjkejingsitedb2', # Django对应mysql数据库的名字
        'USER': 'mkj', # 用户
        'PASSWORD': 'M@ikejing123', # 密码
        'HOST': 'localhost', # ip
        'PORT': '3306', # 端口
    }
}

注意分配用户:
我们上面的操作都是MySQL的root用户,有最高权限,不能直接写在这里,因此需要分配对应数据库权限的用户。

# 查看用户
select host, user from user;

# 创建新用户
create user 'xxx'@'localhost' identified by 'xxxx';
grant all privileges on mikejingsitedb.* to 'mkj'@'localhost'; # 分配mikejingsitedb的所有表权限
flush privileges; # 刷新

# 修改已有权限用户
# grant all privileges on mikejingsitedb.* to '已有用户'@'localhost'; # 分配mikejingsitedb的所有表权限
# flush privileges; # 刷新

# 登录查看
mysql -u mkj -p 
show databases; # 只能查看对应的数据库

2.启动测试
如果这个时候直接运行python manager.py runserver会提示没有迁移,先执行python manager.py migrate执行迁移。这里正常情况下就会报错了,因为Django不同版本的数据库操作类不同,提示是没有clientmysql类似的这种中,Mac中你直接安装pip install xxx也会安装不上,Windows会有whl版本直接安装编译好的插件。Mac网上那些文章都是直接安装pip install pymysql但是后续的问题就来了。

解决方法:
Django连接MySQL时默认使用MySQLdb驱动,但MySQLdb不支持Python3,因此这里将MySQL驱动设置为pymysql,使用 pip install pymysql 进行安装,然后在工程文件__init__.py添加以下代码即可。

#安装pymysql
pip install pymysql

#__init__.py
import pymysql
pymysql.install_as_MySQLdb()

又会报错

django2.2/mysql ImproperlyConfigured: mysqlclient 1.3.13 or newer is
required; you have 0.9.3

第一种:
django降到2.1.4版本就OK了
第二种:修改源码
在这里插入图片描述

# 找到base.py文件,注释掉 base.py 中如下部分(35/36行)
if version < (1, 3, 3):
     raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)

此时还不够,依然会报错AttributeError: ‘str’ object has no attribute ‘decode’

#找到operations.py文件(46行,版本不同行数不同哈~自个儿find一下),将decode改为encode
#linux vim 查找快捷键:?decode
if query is not None:
    query = query.decode(errors='replace')
return query
#改为
if query is not None:
    query = query.encode(errors='replace')
return query

OK,问题解决,可以进行迁移了。

3.执行迁移
python manager.py migrate,可以看到log都是成功的,就说明表迁移成功。

4.SQLite数据导出,导入MySQL

# 打开settings.py 的 sqlite注解 注释掉mysql 导出
python manager.py dumpdata > data.json

# 打开settings.py 的 mysql注解 注释掉sqlite 导入
python manage.py loaddata data.json

确保Mysql用户表里为空的,如果之前有迁移过数据到Mysql,有可能会出错。注意出错的时候所报的错误信息。如果提示有重复主键,那需要先删掉数据。这些数据是在给MySQL数据库应用迁移文件的时候产生的,一般是content_type相关的表。

use 你的数据库名;
delete from auth_permission;
delete from django_content_type;

继续导入

python manage.py loaddata data.json
Installed 1057 object(s) from 1 fixture(s)

这里导入数据,如果你编码问题,就会遇到各种报错,比如这种编码问题报错
我们建库的时候已经制定了utf8mb4,可以看下实际的表数据
在这里插入图片描述

成功入库,这个时候如果你用到的缓存表来缓存数据,记得在执行下

python manager.py createcachetable
python manager.py runserver

迁移成功,能看到我之前的博客网站数据都正常,而且也能登录,搞定。那么到时候部署到服务器,也是一样的操作

参考文章:
SQL查询语句相关模糊搜索
修改root密码
优雅的忘记密码
MySQL安装
官网忘记密码介绍
django2.2/mysql ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3
mysql时区查询
mysql时区导入
数据库迁移中文资料
COLLATE和utf8mb4
Python3出现"No module named ‘MySQLdb’"问题-以及使用PyMySQL连接数据库

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页