把MySQL数据库从Windows迁移到Linux,最简单的方法当然是采用文件拷贝的方式进行迁移。这里当然是有坑的,首先想到是不同操作系统之间的字节序的问题,Oracle的RMAN可以实现相同字节序跨平台迁移数据库,还可以对不同的字节序进行转换,下面先在Oracle的视图V$TRANSPORTABLE_PLATFORM上查询一下Windows平台和Linux的字节序是否相同:
SQL> COLUMN PLATFORM_NAME FORMAT A32 set linesize 200 SELECT PLATFORM_NAME,ENDIAN_FORMAT FROM V$TRANSPORTABLE_PLATFORM where platform_name like '%Windows%' or platform_name like '%Linux%';SQL> SQL> PLATFORM_NAME ENDIAN_FORMAT -------------------------------- -------------- Microsoft Windows IA (32-bit) Little Linux IA (32-bit) Little Linux IA (64-bit) Little Microsoft Windows IA (64-bit) Little IBM zSeries Based Linux Big Linux x86 64-bit Little Microsoft Windows x86 64-bit Little IBM Power Based Linux Big Linux OS (S64) Big 9 rows selected.
查询发现Windows平台和Linux平台都是小字节序,因此应该可以使用拷贝的方式从Windows迁移到Linux的。
另外一个需要考虑的是系统参数lower_case_table_names的设置问题。不同平台的lower_case_table_names的设置会影响数据的迁移。这个参数有3个值:
如果设置为0,表名将按指定方式存储,并且比较区分大小写。
如果设置为1,表名在磁盘上以小写形式存储,比较不区分大小写。
如果设置为2,表名按给定的格式存储,但以小写形式进行比较。
此选项也适用于数据库名称和表别名。这个参数在在不同的平台上有不同的默认值:
在Windows上,默认值为1,不支持0。
在macOS上,默认值为2。
在Linux上,默认值为0,不支持值2。
在MySQL 8之前可以通可以通过配置文件修改这个参数,修改后重启数据库生效。8.0 之后的版本,只允许在数据库初始化时指定,之后就不允许修改了。
目标数据库的MySQL版本号大于或等于源数据库的版本号,不同版本号之间迁移不支持crash recovery。
从Linux平台迁移到Windows平台
Linux平台系统参数lower_case_table_names默认是0,建库的时候是使用大小写敏感的方式创建的数据库,移到Windows平台会因为Windows不区分大小写而失败。如果要把MySQL数据从Linux平台迁移到Windows平台,需要在创建数据库的时候就指定系统参数lower_case_table_names为1。下面是以默认方式进行数据库迁移失败的过程。
把数据库文件从Linux平台拷贝到Windows平台:
C:\Program Files\PuTTY>pscp -r root@192.168.???.???:/var/lib/mysql/* c:\linux_data The server's host key is not cached. You have no guarantee that the server is the computer you think it is. The server's ecdsa-sha2-nistp256 key fingerprint is: ecdsa-sha2-nistp256 256 SHA256:rpW9pEeCVuwsvUW2ZamjbSfT25354IOu51Bm05S+MvE If you trust this host, enter "y" to add the key to PuTTY's cache and carry on connecting. If you want to carry on connecting just once, without adding the key to the cache, enter "n". If you do not trust this host, press Return to abandon the connection. Store key in cache? (y/n, Return cancels connection, i for more info) y root@192.168.???.???'s password: ibdata1 | 12288 kB | 12288.0 kB/s | ETA: 00:00:00 | 100% ib_logfile1 | 49152 kB | 24576.0 kB/s | ETA: 00:00:00 | 100% undo_001 | 12288 kB | 6144.0 kB/s | ETA: 00:00:00 | 100% undo_002 | 12288 kB | 12288.0 kB/s | ETA: 00:00:00 | 100% ib_logfile0 | 49152 kB | 16384.0 kB/s | ETA: 00:00:00 | 100% mysql.ibd | 25600 kB | 25600.0 kB/s | ETA: 00:00:00 | 100% ...
文件传输完成后,启动mysqld:
C:\Program Files\MySQL\MySQL Server 8.0\bin>mysqld --no-defaults --console --datadir=c:\linux_data 2021-09-09T02:56:23.406039Z 0 [System] [MY-010116] [Server] C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe (mysqld 8.0.26) starting as process 15396 2021-09-09T02:56:23.661170Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started. 2021-09-09T02:56:25.535866Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended. 2021-09-09T02:56:25.611530Z 1 [ERROR] [MY-011087] [Server] Different lower_case_table_names settings for server ('1') and data dictionary ('0'). 2021-09-09T02:56:25.613984Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed. 2021-09-09T02:56:25.619065Z 0 [ERROR] [MY-010119] [Server] Aborting 2021-09-09T02:56:26.095979Z 0 [System] [MY-010910] [Server] C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe: Shutdown complete (mysqld 8.0.26) MySQL Community Server - GPL.
提示因为服务的参数lower_case_table_names settings和数据字典里面这个参数不同,无法启动,因为数据是从Linux平台来的,数据字典里面这个参数是0,这是创建数据库的时候决定的,无法进行修改。但可以把服务启动时候的参数改成0,再试一下:
C:\Program Files\MySQL\MySQL Server 8.0\bin>mysqld --no-defaults --console --datadir=c:\linux_data --lower_case_table_names=0 2021-09-09T02:56:47.120358Z 0 [System] [MY-010116] [Server] C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe (mysqld 8.0.26) starting as process 14188 2021-09-09T02:56:47.127009Z 0 [ERROR] [MY-010158] [Server] The server option 'lower_case_table_names' is configured to use case sensitive table names but the data directory is on a case-insensitive file system which is an unsupported combination. Please consider either using a case sensitive file system for your data directory or switching to a case-insensitive table name mode. 2021-09-09T02:56:47.136881Z 0 [ERROR] [MY-010119] [Server] Aborting 2021-09-09T02:56:47.138070Z 0 [System] [MY-010910] [Server] C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe: Shutdown complete (mysqld 8.0.26) MySQL Community Server - GPL.
改成对大小写敏感也启动不了,这是自然,windows不支持文件名区分大小写。
从Windows平台迁移到linux平台
进行数据文件的传输:
"c:\Program Files\PuTTY\pscp.exe" -r "C:\ProgramData\MySQL\MySQL Server 8.0\Data\*" root@192.168.18.227:/var/lib/mysql2
把属主从root修改成mysql:
[root@localhost mysql2]# chown -R mysql. ../mysql2
在Linux上启动:
# mysqld --no-defaults --datadir=/var/lib/mysql2 --user=mysql --log-error-verbosity=3 ... 2021-09-08T11:03:04.942353Z 1 [ERROR] [MY-012530] [InnoDB] Unknown redo log format (4). Please follow the instructions at http://dev.mysql.com/doc/refman/8.0/en/ upgrading-downgrading.html. 2021-09-08T11:03:04.942460Z 1 [ERROR] [MY-012930] [InnoDB] Plugin initialization aborted with error Generic error.
因为windows平台的版本高,从高版本到低版本不行。改成同一个版本后启动:
# mysqld --no-defaults --datadir=/var/lib/mysql2 --user=mysql --log-error-verbosity=3 ... 2021-09-08T11:29:12.492105Z 1 [ERROR] [MY-011087] [Server] Different lower_case_table_names settings for server ('0') and data dictionary ('1'). 2021-09-08T11:29:12.492688Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed. 2021-09-08T11:29:12.493236Z 0 [ERROR] [MY-010119] [Server] Aborting
启动失败,又是因为服务的参数lower_case_table_names settings和数据字典里面这个参数不同造成的,把服务的这个参数设置成1后再次启动:
# mysqld --no-defaults --datadir=/var/lib/mysql2 --user=mysql --log-error-verbosity=3 --lower_case_table_names=1 ... mysqld: File '.\binlog.000001' not found (OS errno 2 - No such file or directory) 2021-09-08T11:30:21.679737Z 0 [ERROR] [MY-010958] [Server] Could not open log file. 2021-09-08T11:30:21.680220Z 0 [ERROR] [MY-010041] [Server] Can't init tc log 2021-09-08T11:30:21.680753Z 0 [ERROR] [MY-010119] [Server] Aborting ...
又是启动失败,提示文件.\binlog.000001找不,修改改一下binlog.index中的文件名,把反斜线改成正斜线后再试试:
[root@localhost mysql2]# cat binlog.index .\binlog.000001
再次启动,运行成功!
[root@localhost mysql2]# mysqld --no-defaults --datadir=/var/lib/mysql2 --user=mysql --log-error-verbosity=3 --lower_case_table_names=1 ... 2021-09-08T11:37:11.208204Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
连接进入后检查服务的uuid和数据目录如下:
mysql> select @@server_uuid; +--------------------------------------+ | @@server_uuid | +--------------------------------------+ | 0ba5f5da-0fbb-11ec-bfce-fa163ed6756a | +--------------------------------------+ 1 row in set (0.00 sec) mysql> select @@datadir; +------------------+ | @@datadir | +------------------+ | /var/lib/mysql2/ | +------------------+ 1 row in set (0.00 sec)
发现是和windows上的MySQL同一个uuid,数据目录是从windows上传输过来的数据目录。
总结
从windows到linux可以直接拷贝方式传输数据库,兼容性如下:
源平台 目标平台 MySQL版本 是否可以拷贝数据文件
Windows Linux >8.0 可以
Linux Windows >8.0 不行
Windows Linux <8.0 可以
Linux Windows <8.0 可以
说明:
这里列举的是默认设置,如果在创建数据库的时候在Linux平台上设置–lower_case_table_names=1,在MySQL 8上也可以把Linux平台上的数据拷贝到Windows平台。
应该在数据库关闭或者设置了全局读锁(flush tables with read lock)后进行文件拷贝。