使用 Docker 来管理 MySQL、Redis 等各种中间件是十分方便的,无论是生产环境,还是开发环境都非常方便。今天来说一下我用 Docker 来管理 MySQL 时遇到的一个小坑。
在 Docker 下部署 MySQL
在 Docker 下部署 MySQL 是很方便的,通过几条命令就可以轻轻松松的下载镜像并完成安装部署。
首先,拉取MySQL镜像:
%dockerpullmysql:latestlatest:Pullingfromlibrary/mysqla076a628af6f:Alreadyexistsf6c208f3f991:Pullcomplete88a9455a9165:Pullcomplete406c9b8427c6:Pullcomplete7c88599c0b25:Pullcomplete25b5c6debdaf:Pullcomplete43a5816f1617:Pullcomplete1a8c919e89bf:Pullcomplete9f3cf4bd1a07:Pullcomplete80539cea118d:Pullcomplete201b3cad54ce:Pullcomplete944ba37e1c06:PullcompleteDigest:sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8cStatus:Downloadednewerimageformysql:latestdocker.io/library/mysql:latest
上面的命令是拉取最新的MySQL镜像。然后查看下载的镜像。
%dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmysqllatestc8562eaf9d812monthsago546MB
从结果可以看到,已经有了 mysql 的 image,然后我们启动运行容器,命令如下。
%dockerrun-itd--namemysql-test-p3306:3306-eMYSQL_ROOT_PASSWORD=123456mysql19949fb03dd9700bb9e57524317fca477c0407d82ae1ff0cbdd4669b0af6c778
我们来查看容器的状态。
%dockerpsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES19949fb03dd9mysql"docker-entrypoint.s…"53secondsagoUp52seconds0.0.0.0:3306->3306/tcp,33060/tcpmysql-test
此时就可使用 Navicat 等客户端工具来连接 MySQL 了。当然也可以进入 Docker 中进行管理。
%dockerexec-itmysql-test/bin/bashroot@19949fb03dd9:/# mysql -u root -pEnterpassword:WelcometotheMySQLmonitor.Commandsendwith;or\g.YourMySQLconnectionidis42726Serverversion:8.0.23MySQLCommunityServer-GPLCopyright(c)2000,2021,Oracleand/oritsaffiliates.OracleisaregisteredtrademarkofOracleCorporationand/oritsaffiliates.Othernamesmaybetrademarksoftheirrespectiveowners.Type'help;'or'\h'forhelp.Type'\c'toclearthecurrentinputstatement.mysql>
使用 docker exec 命令进入 Docker 后,然后直接使用 mysql 的命令来操作 MySQL。
无论是创建库,还是创建表,包括写一些 SQL 命令看起来一切安好。
小坑
上面看起来还都不错,但是在运行本地的程序时竟然出现了一个报错,报错如下:
badSQLgrammar[];nestedexceptionisjava.sql.SQLSyntaxErrorException:Table'test.SYS_CONFIG'doesn't exist
上面的报错是提示表不存在,但是经过确认后该表是存在的,可能是表名大小写的问题?查看一下。
mysql>showvariableslike'%case%';+------------------------+-------+|Variable_name|Value|+------------------------+-------+|lower_case_file_system|OFF||lower_case_table_names|0|+------------------------+-------+2rowsinset(0.00sec)
配置中 lower_case_table_names 的值为 0,该参数被指定为 0 的时候,那么存储时是按照指定的大小写进行存储的,且在读取时是区分大小写的。该参数如果为 1 时,那么在存储时是使用小写进行存储的,且在读取时是不区分大小的。该值的配置还有 2,这里就不讨论了,而且文档中介绍,只要使用 InnoDB,无论在哪个平台(Linux、MacOS、Windows)下,该参数都要给 1。
那么我们就需要将 lower_case_table_name 的值设置为 1 才可以。
通常情况下,这种参数我们会通过 my.cnf 来进行设置,因此在my.cnf文件中,增加配置项:
lower_case_table_names=1
修改完配置,然后重启 MySQL 的容易,命令如下。
%dockerrestart19949fb03dd9
其中 19949fb03dd9 替换为自己的 container id。在命令行重启后没有什么提示,但是 MySQL 不能使用。检查日志,发现启动失败,在日志中存在错误提示:
[ERROR][MY-011087][Server]Differentlower_case_table_namessettingsforserver('1')anddatadictionary('0').
配置文件与数据字典的配置不同,从而导致无法启动。数据字典是在 MySQL 数据库服务器初始化时设置的,而配置则不能与数据字典不一致,这是 MySQL 的一个限制。因此,我们需要重新创建一个 MySQL 的容器,并在启动时给 lower-case-table-names 参数设置为 1 即可。
%dockerrun-itd--namemysql-new-p3306:3306-eMYSQL_ROOT_PASSWORD=123456mysql--lower-case-table-names=15669d0d7c1776d2dc296a334484855f3c0c0a7d48d917e98d532e3a50b9c66d5%dockerexec-itmysql-new/bin/bashroot@5669d0d7c177:/# mysql -u root -pEnterpassword:WelcometotheMySQLmonitor.Commandsendwith;or\g.YourMySQLconnectionidis86Serverversion:8.0.23MySQLCommunityServer-GPLCopyright(c)2000,2021,Oracleand/oritsaffiliates.OracleisaregisteredtrademarkofOracleCorporationand/oritsaffiliates.Othernamesmaybetrademarksoftheirrespectiveowners.Type'help;'or'\h'forhelp.Type'\c'toclearthecurrentinputstatement.mysql>showvariableslike'%case%';+------------------------+-------+|Variable_name|Value|+------------------------+-------+|lower_case_file_system|OFF||lower_case_table_names|1|+------------------------+-------+2rowsinset(0.00sec)
这样 MySQL 的小坑就解决了。
总结
以前使用 MySQL 没有遇到过此类的问题,这也是在 Docker 中使用 MySQL 时遇到的问题。