专职DBA-MySQL常用的两种升级方法 周万春 MySQL5.5.54升级到MySQL5.6.35 #---------------------------------------------------------------------------------------- 第1种升级方案:in-place原地升级 1.停止MySQL 5.5.54 db01 [~] 2020-06-30 23:07:03 root@pts/0 # mysql -udba -p mysql> show variables like '%sql_mode%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | sql_mode | | +---------------+-------+ 1 row in set (0.00 sec) mysql> set global innodb_fast_shutdown=0; Query OK, 0 rows affected (0.00 sec) db01 [~] 2020-06-30 23:08:35 root@pts/2 # /etc/init.d/mysqld stop Shutting down MySQL.... [ OK ] db01 [~] 2020-06-30 23:09:03 root@pts/2 # ps -ef | grep mysqld | grep -v grep db01 [~] 2020-06-30 23:09:09 root@pts/2 # netstat -lnp | grep mysqld 2.在my.cnf中添加skip_grant_tables参数 db01 [~] 2020-06-30 23:09:45 root@pts/2 # cat /etc/my.cnf [client] socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 [mysqld] user=mysql basedir = /usr/local/mysql socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 pid-file=/home/mysql/data/mysqldata1/sock/mysql.pid # pid文件所在路径 datadir=/home/mysql/data/mysqldata1/mydata # 数据文件路径 tmpdir=/home/mysql/data/mysqldata1/tmpdir # 存放临时文件的路径 log-error=/home/mysql/data/mysqldata1/log/error.log slow_query_log slow_query_log_file=/home/mysql/data/mysqldata1/slowlog/slow-query.log log-bin=/home/mysql/data/mysqldata1/binlog/mysql-bin relay-log=/home/mysql/data/mysqldata1/relaylog/mysql-relay-bin innodb_data_home_dir = /home/mysql/data/mysqldata1/innodb_ts innodb_log_group_home_dir = /home/mysql/data/mysqldata1/innodb_log #innodb_undo_directory = /home/mysql/data/mysqldata1/undo/ skip_grant_tables 3.替换basedir db01 [~] 2020-06-30 23:09:49 root@pts/2 # cd /disk/ db01 [/disk] 2020-06-30 23:11:12 root@pts/2 # tar -xf mysql-5.6.35-linux-glibc2.5-x86_64.tar.gz -C /home/mysql/program/ db01 [/disk] 2020-06-30 23:11:45 root@pts/2 # unlink /usr/local/mysql db01 [/disk] 2020-06-30 23:11:57 root@pts/2 # ln -s /home/mysql/program/mysql-5.6.35-linux-glibc2.5-x86_64/ /usr/local/mysql db01 [/disk] 2020-06-30 23:12:11 root@pts/2 # chown -R mysql:mysql /home/mysql/program/mysql-5.6.35-linux-glibc2.5-x86_64/ 4.备份数据 db01 [/disk] 2020-06-30 23:13:12 root@pts/2 # cd /home/mysql/ db01 [/home/mysql] 2020-06-30 23:14:32 root@pts/2 # cp -a data data_bak 5.启动并升级MySQL db01 [~] 2020-06-30 23:16:04 root@pts/0 # cp -a /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld db01 [~] 2020-06-30 23:16:19 root@pts/0 # chmod +x /etc/init.d/mysqld db01 [~] 2020-06-30 23:16:29 root@pts/0 # /etc/init.d/mysqld start Starting MySQL.. [ OK ] db01 [~] 2020-06-30 23:17:22 root@pts/0 # mysql mysql> select user(),current_user(); +--------+----------------+ | user() | current_user() | +--------+----------------+ | root@ | @ | +--------+----------------+ 1 row in set (0.00 sec) 使用mysql_upgrade命令升级数据字典库。注意:使用mysql_upgrade命令时需要用管理员账号,且带上用户名和密码,否则会报出拒绝访问的错误。 注意:过程中每一步都要输出OK,且最后输出一个总的OK,看到这些OK,就表示所有的数据字典表升级成功了。 db01 [~] 2020-06-30 23:18:13 root@pts/0 # mysql_upgrade -uroot -p Enter password: Looking for 'mysql' as: mysql Looking for 'mysqlcheck' as: mysqlcheck Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. mysql.columns_priv OK mysql.db OK mysql.event OK mysql.func OK mysql.general_log OK mysql.help_category OK mysql.help_keyword OK mysql.help_relation OK mysql.help_topic OK mysql.host OK mysql.ndb_binlog_index OK mysql.plugin OK mysql.proc OK mysql.procs_priv OK mysql.proxies_priv OK mysql.servers OK mysql.slow_log OK mysql.tables_priv OK mysql.time_zone OK mysql.time_zone_leap_second OK mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK Running 'mysql_fix_privilege_tables'... Warning: Using a password on the command line interface can be insecure. Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. app01.t1 OK OK 6.重启MySQL并访问数据,测试升级之后能否正常访问 db01 [~] 2020-06-30 23:19:54 root@pts/0 # cat /etc/my.cnf [client] socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 [mysqld] user=mysql basedir = /usr/local/mysql socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 pid-file=/home/mysql/data/mysqldata1/sock/mysql.pid # pid文件所在路径 datadir=/home/mysql/data/mysqldata1/mydata # 数据文件路径 tmpdir=/home/mysql/data/mysqldata1/tmpdir # 存放临时文件的路径 log-error=/home/mysql/data/mysqldata1/log/error.log slow_query_log slow_query_log_file=/home/mysql/data/mysqldata1/slowlog/slow-query.log log-bin=/home/mysql/data/mysqldata1/binlog/mysql-bin relay-log=/home/mysql/data/mysqldata1/relaylog/mysql-relay-bin innodb_data_home_dir = /home/mysql/data/mysqldata1/innodb_ts innodb_log_group_home_dir = /home/mysql/data/mysqldata1/innodb_log #innodb_undo_directory = /home/mysql/data/mysqldata1/undo/ #skip_grant_tables db01 [~] 2020-06-30 23:19:56 root@pts/0 # /etc/init.d/mysqld restart Shutting down MySQL.. [ OK ] Starting MySQL. [ OK ] db01 [~] 2020-06-30 23:21:19 root@pts/0 # mysql -udev -p app01 mysql> select user(),current_user(); +---------------+----------------+ | user() | current_user() | +---------------+----------------+ | dev@localhost | dev@% | +---------------+----------------+ 1 row in set (0.00 sec) mysql> select version(); +------------+ | version() | +------------+ | 5.6.35-log | +------------+ 1 row in set (0.00 sec) mysql> show grants; +--------------------------------------------------------------------------------------------------------+ | Grants for dev@% | +--------------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'dev'@'%' IDENTIFIED BY PASSWORD <secret> | | GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, CREATE ROUTINE, ALTER ROUTINE ON `app01`.* TO 'dev'@'%' | +--------------------------------------------------------------------------------------------------------+ 2 rows in set (0.00 sec) mysql> select * from t1; +----+--------------------------------------+------+------+---------------------+ | id | c1 | c2 | c3 | intime | +----+--------------------------------------+------+------+---------------------+ | 1 | bf7042b9-bae2-11ea-b650-00163e1693be | db01 | 3306 | 2020-06-30 23:02:42 | +----+--------------------------------------+------+------+---------------------+ 1 row in set (0.00 sec) mysql> insert into t1(c1,c2,c3) values(uuid(),@@hostname,@@port); Query OK, 1 row affected, 2 warnings (0.00 sec) mysql> select * from t1; +----+--------------------------------------+------+------+---------------------+ | id | c1 | c2 | c3 | intime | +----+--------------------------------------+------+------+---------------------+ | 1 | bf7042b9-bae2-11ea-b650-00163e1693be | db01 | 3306 | 2020-06-30 23:02:42 | | 2 | 83d8dcbc-bae5-11ea-8ebf-00163e1693be | db01 | 3306 | 2020-06-30 23:22:31 | +----+--------------------------------------+------+------+---------------------+ 2 rows in set (0.00 sec) 如果需要修改sql_mode值,则修改全局,并把sql_mode加到my.cnf中 db01 [~] 2020-06-30 23:23:19 root@pts/0 # mysql -udba -p mysql> show variables like '%sql_mode%'; +---------------+------------------------+ | Variable_name | Value | +---------------+------------------------+ | sql_mode | NO_ENGINE_SUBSTITUTION | +---------------+------------------------+ 1 row in set (0.00 sec) mysql> set global sql_mode=''; Query OK, 0 rows affected (0.00 sec) #---------------------------------------------------------------------------------------- 第2张升级方案:mysqldump逻辑导出导入升级 环境准备到MySQL5.5 db01 [~] 2020-06-30 23:28:22 root@pts/0 # /etc/init.d/mysqld stop Shutting down MySQL.. [ OK ] db01 [~] 2020-06-30 23:28:34 root@pts/0 # unlink /usr/local/mysql db01 [~] 2020-06-30 23:29:10 root@pts/0 # cd /home/mysql/ db01 [/home/mysql] 2020-06-30 23:29:34 root@pts/0 # mv data data_5.6 db01 [/home/mysql] 2020-06-30 23:29:51 root@pts/0 # mv data_bak data db01 [~] 2020-06-30 23:30:33 root@pts/0 # ln -s /home/mysql/program/mysql-5.5.54-linux2.6-x86_64/ /usr/local/mysql db01 [~] 2020-06-30 23:30:46 root@pts/0 # rm -rf /etc/init.d/mysqld db01 [~] 2020-06-30 23:30:58 root@pts/0 # cp -a /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld db01 [~] 2020-06-30 23:31:31 root@pts/0 # /etc/init.d/mysqld start Starting MySQL.. [ OK ] 以上MySQL5.5.54数据库环境已经就绪 1.使用mysqldump备份整个实例 db01 [~] 2020-06-30 23:31:53 root@pts/0 # mysql -udba -p mysql> show variables like '%sql_mode%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | sql_mode | | +---------------+-------+ 1 row in set (0.00 sec) mysql> flush table with read lock; Query OK, 0 rows affected (0.00 sec) mysql> set global read_only=ON; Query OK, 0 rows affected (0.00 sec) mysql> q Bye db01 [~] 2020-06-30 23:50:13 root@pts/4 # mysqldump -udba -p --add-drop-table --routines --events --all-databases --force > /tmp/data-for-upgrade.sql Enter password: 2.安装MySQL 5.6.35 db01 [~] 2020-06-30 23:51:10 root@pts/4 # /etc/init.d/mysqld stop Shutting down MySQL.. [ OK ] db01 [~] 2020-06-30 23:51:33 root@pts/4 # ps -ef | grep mysqld | grep -v grep db01 [~] 2020-06-30 23:51:37 root@pts/4 # netstat -lnp | grep mysqld db01 [~] 2020-06-30 23:51:43 root@pts/4 # unlink /usr/local/mysql db01 [~] 2020-06-30 23:56:21 root@pts/0 # ln -s /home/mysql/program/mysql-5.6.35-linux-glibc2.5-x86_64/ /usr/local/mysql db01 [~] 2020-06-30 23:52:37 root@pts/4 # cd /home/mysql/ db01 [/home/mysql] 2020-06-30 23:52:54 root@pts/4 # cp -a data data_bak db01 [/home/mysql] 2020-06-30 23:53:37 root@pts/4 # cd data/mysqldata1/ db01 [/home/mysql/data/mysqldata1] 2020-06-30 23:55:03 root@pts/4 # rm -rf ./{binlog,innodb_log,innodb_ts,log,mydata,slowlog,sock,tmpdir,undo}/* db01 [/home/mysql/data/mysqldata1] 2020-06-30 23:55:08 root@pts/4 # tree ./ ./ |-- binlog |-- innodb_log |-- innodb_ts |-- log |-- mydata |-- relaylog |-- slowlog |-- sock |-- tmpdir `-- undo 10 directories, 0 files db01 [/home/mysql/data/mysqldata1] 2020-06-30 23:56:44 root@pts/0 # cd /usr/local/mysql/ db01 [/usr/local/mysql] 2020-06-30 23:56:47 root@pts/0 # ./scripts/mysql_install_db --defaults-file=/home/mysql/conf/my.cnf --user=mysql 3.导入MySQL 5.5.54的备份数据 db01 [~] 2020-06-30 23:58:09 root@pts/0 # rm -rf /etc/init.d/mysqld db01 [~] 2020-06-30 23:58:14 root@pts/0 # cp -a /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld db01 [~] 2020-06-30 23:58:23 root@pts/0 # chmod +x /etc/init.d/mysqld db01 [~] 2020-07-01 00:12:34 root@pts/0 # cat /etc/my.cnf [client] socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 [mysqld] user=mysql basedir = /usr/local/mysql socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 pid-file=/home/mysql/data/mysqldata1/sock/mysql.pid # pid文件所在路径 datadir=/home/mysql/data/mysqldata1/mydata # 数据文件路径 tmpdir=/home/mysql/data/mysqldata1/tmpdir # 存放临时文件的路径 log-error=/home/mysql/data/mysqldata1/log/error.log slow_query_log slow_query_log_file=/home/mysql/data/mysqldata1/slowlog/slow-query.log log-bin=/home/mysql/data/mysqldata1/binlog/mysql-bin relay-log=/home/mysql/data/mysqldata1/relaylog/mysql-relay-bin innodb_data_home_dir = /home/mysql/data/mysqldata1/innodb_ts innodb_log_group_home_dir = /home/mysql/data/mysqldata1/innodb_log #innodb_undo_directory = /home/mysql/data/mysqldata1/undo/ skip_grant_tables db01 [~] 2020-06-30 23:58:33 root@pts/0 # /etc/init.d/mysqld start Starting MySQL. [ OK ] db01 [~] 2020-07-01 00:00:24 root@pts/0 # mysql -f < /tmp/data-for-upgrade.sql db01 [~] 2020-07-01 00:00:54 root@pts/0 # echo $? 0 4.执行mysql_upgrade升级数据字典库 db01 [~] 2020-07-01 00:13:31 root@pts/0 # mysql_upgrade -uroot -p Enter password: Looking for 'mysql' as: mysql Looking for 'mysqlcheck' as: mysqlcheck Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. mysql.columns_priv OK mysql.db OK mysql.event OK mysql.func OK mysql.general_log OK mysql.help_category OK mysql.help_keyword OK mysql.help_relation OK mysql.help_topic OK mysql.host OK mysql.innodb_index_stats OK mysql.innodb_table_stats OK mysql.ndb_binlog_index OK mysql.plugin OK mysql.proc OK mysql.procs_priv OK mysql.proxies_priv OK mysql.servers OK mysql.slave_master_info OK mysql.slave_relay_log_info OK mysql.slave_worker_info OK mysql.slow_log OK mysql.tables_priv OK mysql.time_zone OK mysql.time_zone_leap_second OK mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK Running 'mysql_fix_privilege_tables'... Warning: Using a password on the command line interface can be insecure. Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. Running 'mysqlcheck' with connection arguments: '--socket=/home/mysql/data/mysqldata1/sock/mysql.sock' Warning: Using a password on the command line interface can be insecure. app01.t1 OK OK 5.重启MySQL并访问数据,测试升级之后能否正常访问 去掉配置文件中的skip_grant_tables参数并重启MySQL db01 [~] 2020-07-01 00:14:29 root@pts/0 # cat /etc/my.cnf [client] socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 [mysqld] user=mysql basedir = /usr/local/mysql socket=/home/mysql/data/mysqldata1/sock/mysql.sock # sock文件所在路径 pid-file=/home/mysql/data/mysqldata1/sock/mysql.pid # pid文件所在路径 datadir=/home/mysql/data/mysqldata1/mydata # 数据文件路径 tmpdir=/home/mysql/data/mysqldata1/tmpdir # 存放临时文件的路径 log-error=/home/mysql/data/mysqldata1/log/error.log slow_query_log slow_query_log_file=/home/mysql/data/mysqldata1/slowlog/slow-query.log log-bin=/home/mysql/data/mysqldata1/binlog/mysql-bin relay-log=/home/mysql/data/mysqldata1/relaylog/mysql-relay-bin innodb_data_home_dir = /home/mysql/data/mysqldata1/innodb_ts innodb_log_group_home_dir = /home/mysql/data/mysqldata1/innodb_log #innodb_undo_directory = /home/mysql/data/mysqldata1/undo/ #skip_grant_tables db01 [~] 2020-07-01 00:14:32 root@pts/0 # /etc/init.d/mysqld restart Shutting down MySQL.. [ OK ] Starting MySQL. [ OK ] db01 [~] 2020-07-01 00:15:21 root@pts/0 # mysql -udev -p app01 mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | app01 | +--------------------+ 2 rows in set (0.00 sec) mysql> select * from t1; +----+--------------------------------------+------+------+---------------------+ | id | c1 | c2 | c3 | intime | +----+--------------------------------------+------+------+---------------------+ | 1 | bf7042b9-bae2-11ea-b650-00163e1693be | db01 | 3306 | 2020-06-30 23:02:42 | +----+--------------------------------------+------+------+---------------------+ 1 row in set (0.00 sec) mysql> insert into t1(c1,c2,c3) values(uuid(),@@hostname,@@port); Query OK, 1 row affected, 2 warnings (0.00 sec) mysql> select * from t1; +----+--------------------------------------+------+------+---------------------+ | id | c1 | c2 | c3 | intime | +----+--------------------------------------+------+------+---------------------+ | 1 | bf7042b9-bae2-11ea-b650-00163e1693be | db01 | 3306 | 2020-06-30 23:02:42 | | 2 | 04e0160f-baed-11ea-bff3-00163e1693be | db01 | 3306 | 2020-07-01 00:16:14 | +----+--------------------------------------+------+------+---------------------+ 2 rows in set (0.00 sec) db01 [~] 2020-07-01 00:17:03 root@pts/0 # mysql -udba -p mysql> show variables like '%sql_mode%'; +---------------+--------------------------------------------+ | Variable_name | Value | +---------------+--------------------------------------------+ | sql_mode | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | +---------------+--------------------------------------------+ 1 row in set (0.00 sec) 如果需要修改sql_mode值,则修改全局,并把sql_mode加到my.cnf中 mysql> set global sql_mode='NO_ENGINE_SUBSTITUTION'; Query OK, 0 rows affected (0.00 sec) 升级注意事项 在主库中创建一个带有主键的InnoDB表(低于MySQL 5.7版本的库),针对主键字段设置为null(虽然这个例子不是很恰当,但这里仅限于说明从MySQL 5.6升级到MySQL 5.7需要谨慎,在同一个复制架构中不建议存在多个版本) mysql> show create table test; ...... 1 row in set (0.00 sec) mysql> select version(); ...... 1 row in set (0.00 sec) mysql> alter table test modify column id int(10) unsigned NULL; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table test; ...... 1 row in set (0.00 sec) ## 解析binlog查看 [root@localhost data]# mysqlbinlog -vv mysql-bin.000203 ...... # 在主库中创建一个带有主键的InnoDB表(高于或等于MySQL 5.7版本的库),针对主键字段设置为null mysql> show create table test; ...... 1 row in set (0.00 sec) mysql> select version(); ...... 1 row in set (0.00 sec) mysql> alter table test modify column id int(10) unsigned NULL; ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead MySQL5.7版本不允许对主键设置null属性操作,MySQL5.6版本是允许对主键设置null属性操作的, 但会在存储引擎内部自动忽略这个动作。 虽然忽略了这个动作,但是这条语句却执行成功了,已经记录到binlog中。 如果从库是MySQL5.7,就会在SQL线程重放到这条SQL语句时报错, ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead.