MySQL关闭,kill还是kill -9 ?

系统运维2025-11-05 13:57:0066714

本文转载自微信公众号「DBA随笔」,作者DBA随笔。转载本文请联系DBA随笔公众号。

今天在线上遇到了一个MySQL字符比较的问题,感觉很有意思,专门研究了下,估计大家都没有遇到过,这里跟大家分享一下。

MySQL关闭,kill还是kill -9 ?

1.背景

背景介绍:

MySQL里面有一张表,根据where条件匹配查询某一条记录的时候,手误输入了一个空格,发现这一条数据仍然能查出来,我建了一个测试表,还原如下:

复制22:57:02> create table t00 (id int primary key,name varchar(10));Query OK, 0 rows affected (0.01 sec)22:57:11> insert into t00 values (1,aaa),(2,bbb);Query OK, 2 rows affected (0.00 sec)Records: 2 Duplicates: 0 Warnings: 022:57:22> select * from t00 where name=aaa;+----+------+| id | name |+----+------+| 1 | aaa |+----+------+1 row in set (0.00 sec)22:57:32> select * from t00 where name=aaa ;+----+------+| id | name |+----+------+| 1 | aaa |+----+------+1 row in set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.

插入(1,aaa)这条记录,使用where=aaa和aaa 这两个条件去匹配,居然都能够查到这条记录。

一开始我怀疑是这个8.0.19版本MySQL实例配置有问题,换了一个5.5低版本的MySQL实例,再次测试,还是复现这个问题。看来不是版本上的问题,一定是某种配置的问题。

晚上回到家,又用了自己搭建的一个8.0.22版本的源码下载MySQL实例重新执行上面的命令,竟然惊奇的发现,不复现了。。。晕死。8.0.22版本测试的结果是:

复制23:35:30>>select * from t0;+------+------+| id | name |+------+------+| 1 | aaa || 2 | bbb |+------+------+2 rows in set (0.01 sec)23:35:34>>select * from t0 where name=aaa;+------+------+| id | name |+------+------+| 1 | aaa |+------+------+1 row in set (0.00 sec)23:35:46>>select * from t0 where name=aaa ;Empty set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.

2.分析思路

1)为什么aaa和aaa 一样?

首先我用命令在MySQL上检测了一下这两个字符串在MySQL中是否一样:

复制### MySQL实例一

23:39:09> select aaa = aaa ;+------------------+| aaa = aaa |+------------------+| 1 |+------------------+1 row in set (0.00 sec)

### MySQL实例二

23:35:54>>select aaa = aaa ;+------------------+| aaa = aaa |+------------------+| 0 |+------------------+1 row in set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.

从上面的结果可以看出来,这两个实例上,关于字符的比较规则不一样。

到这里,可能部分同学就已经知道答案了。不过还是往下再看看。

2)比较规则哪里不一样?

我们可以用下面的命令,先看一下utf8相关的字符集下的比较规则,如下:

复制23:45:18> show collation like utf8%;+----------------------------+---------+-----+---------+----------+---------+---------------+| Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute |+----------------------------+---------+-----+---------+----------+---------+---------------+| utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD || utf8mb4_0900_as_ci | utf8mb4 | 305 | | Yes | 0 | NO PAD || utf8mb4_0900_as_cs | utf8mb4 | 278 | | Yes | 0 | NO PAD || utf8mb4_0900_bin | utf8mb4 | 309 | | Yes | 1 | NO PAD || utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 | PAD SPACE || utf8mb4_croatian_ci | utf8mb4 | 245 | | Yes | 8 | PAD SPACE || utf8mb4_cs_0900_ai_ci | utf8mb4 | 266 | | Yes | 0 | NO PAD || utf8mb4_cs_0900_as_cs | utf8mb4 | 289 | | Yes | 0 | NO PAD || utf8_unicode_ci | utf8 | 192 | | Yes | 8 | PAD SPACE |

........

| utf8_vietnamese_ci | utf8 | 215 | | Yes | 8 | PAD SPACE |+----------------------------+---------+-----+---------+----------+---------+---------------+103 rows in set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.

在最后一列,我们可以看到一个pad属性,这个属性里面包含2个值,分别是no pad 和pad space。

3)尝试去官方文档中查找这俩属性的意思

果然,不出意外,服务器租用找到了一些蛛丝马迹:

https://dev.mysql.com/doc/refman/8.0/en/char.html

To determine the pad attribute for a collation, use the INFORMATION_SCHEMA COLLATIONS table, which has a PAD_ATTRIBUTE column.

For nonbinary strings (CHAR, VARCHAR, and TEXT values), the string collation pad attribute determines treatment in comparisons of trailing spaces at the end of strings. NO PAD collations treat trailing spaces as significant in comparisons, like any other character. PAD SPACE collations treat trailing spaces as insignificant in comparisons; strings are compared without regard to trailing spaces.

上面这段话描述的意思大概是:

要确定排序规则的填充属性,请使用 information_schema.collations 表,该表具有 pad_attribute 列。

对于非二进制字符串(char,varchar和text),字符串的填充属性决定了比较字符串末尾空格时的处理方式。

NO PAD 排序规则将尾随空格视为重要的比较,更加严格,就像任何其他字符一样;

PAD SPACE 排序规则在比较中将尾随空格视为无关紧要,比较字符串时不考虑尾随空格,也就是有无空格一个样。

这里我们就可以根据实际使用的比较规则来查看对应的pad属性了:

先看实例一:

复制### MySQL实例一

00:01:31>show variables like %colla%;+-------------------------------+--------------------+| Variable_name | Value |+-------------------------------+--------------------+| collation_connection | utf8_general_ci || collation_database | utf8mb4_0900_ai_ci || collation_server | utf8mb4_0900_ai_ci || default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci |+-------------------------------+--------------------+4 rows in set (0.01 sec)00:01:45>select collation_name,character_set_name,pad_attribute from information_schema.collations where collation_name like utf8_general_ci;+-----------------+--------------------+---------------+| collation_name | character_set_name | pad_attribute |+-----------------+--------------------+---------------+| utf8_general_ci | utf8 | PAD SPACE |+-----------------+--------------------+---------------+1 row in set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.

再来看实例二:

复制### 实例二

mysql--root@localhost:(none) 23:53:52>>show variables like %colla%;+-------------------------------+--------------------+| Variable_name | Value |+-------------------------------+--------------------+| collation_connection | utf8mb4_0900_ai_ci || collation_database | utf8mb4_0900_ai_ci || collation_server | utf8mb4_0900_ai_ci || default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci |+-------------------------------+--------------------+4 rows in set (0.00 sec)00:03:47>>select collation_name,character_set_name,pad_attribute from information_schema.collations where collation_name like utf8mb4_0900_ai_ci;+--------------------+--------------------+---------------+| collation_name | character_set_name | pad_attribute |+--------------------+--------------------+---------------+| utf8mb4_0900_ai_ci | utf8mb4 | NO PAD |+--------------------+--------------------+---------------+1 row in set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.

到这里,真相大白。

实例一的连接比较规则是utf8_general_ci,对应的填充规则是pad space属性,代表字符比较过程中,末尾空格不重要,所以加不加空格结果都是一样的;

实例二的连接比较规则是免费信息发布网utf8mb4_0900_ai_ci,对应的填充规则是no pad属性,代表字符比较过程中,末尾空格重要,所以加不加空格结果不一样。

3.如何让字符匹配更严格?

1)修改连接的比较规则为utf8mb4_0900_ai_ci,当然,这个修改需要搭配默认字符集

这个方案比较容易理解,不赘述。

2)使用like模糊匹配进行比较

3)where条件之前,添加binary关键字

上述2、3两种方法可见下面的测试:

复制00:19:13>select * from t00;+----+------+| id | name |+----+------+| 1 | aaa || 2 | bbb |+----+------+2 rows in set (0.00 sec)00:19:18>select * from t00 where name=aaa;+----+------+| id | name |+----+------+| 1 | aaa |+----+------+1 row in set (0.00 sec)00:19:28>select * from t00 where name=aaa ;+----+------+| id | name |+----+------+| 1 | aaa |+----+------+1 row in set (0.00 sec)### 下面两种方案,可以防止aaa 匹配到aaa00:19:31>select * from t00 where name like aaa ;Empty set (0.00 sec)00:19:57>select * from t00 where binary name = aaa ;Empty set (0.00 sec)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.

今天文章就到这里吧。

本文地址:http://www.bhae.cn/news/26d5099923.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

在之前的文章中, 我们讨论过如何在Linux服务器安装各种各样的打印机(当然也包括网络扫描仪)。今天我们将来处理另一端:如何通过桌面客户端来访问网络打印机/扫描仪。网络环境 在这个安装教程中,我们的服务器(Debian Wheezy 7.2版本)的IP地址是192.168.0.10,我们的客户端(Ubuntu 12.04版本)的IP地址是192.168.0.105.注意这两台机器是在同一个网段(192.168.0.0/24).假如我们想允许打印机访问其它网段,我们需要在服务器上修改cupsd.conf文件的以下部分: Order allow,deny Allow localhost Allow from XXX.YYY.ZZZ.*(在上述例子中,我们授予打印机从本地或者任何系统能够访问打印机,这些系统的IPv4地址以XXX.YYY.ZZZ开始。为了验证哪些打印机可以在我们的服务器上适用,我们也可以在服务器上使用lpstat命令,或者浏览网页https://192.168.0.10:631/printers page.root@debian:~# lpstat -a EPSON_Stylus_CX3900 accepting requests since Mon 18 Aug 2014 10:49:33 AM WARSTPDF accepting requests since Mon 06 May 2013 04:46:11 PM WARSTSamsungML1640Series accepting requests since Wed 13 Aug 2014 10:13:47 PM WARST在Ubuntu桌面安装网络打印机 在我们的Ubuntu 12.04的客户端,我们将打开Printing菜单(Dash ->Printing).你会注意到在其它发行版中,这个名字也许会有一点差别(例如会叫做Printers 或者 Print & Fax):还没有打印机添加到我们的客户端:下面是在Ubuntu桌面客户端安装一台网络打印机的一些步骤。1) “Add”按钮将弹出 New Printer 菜单。我们将选择Network printer ->Find Network Printer并输入我们服务器的IP地址,接着点击Find:2) 在最下面我们将会看到可使用的打印机的名称。我们来选择这台三星打印机并按Forward:3) 我们将会被要求填写一些关于我们打印机的信息。当我们输入完成时,将点击 Apply按钮。4) 我们接下来将被询问是否打印一张测试页。让我们点击Print test page吧:这个打印任务将被创建为本地id 2:5)适用我们服务器上的CUPS网络借口,我们可以观察到打印任务已经提交成功了(打印机 ->SamsungML1640系列 ->显示完成任务):我们也可以通过在打印机服务器上运行以下命令显示同样信息: root@debian:~# cat /var/log/cups/page_log | grep -i samsung SamsungML1640Series root 27 [13/Aug/2014:22:15:34 -0300] 1 1 - localhost Test Page - -SamsungML1640Series gacanepa 28 [18/Aug/2014:11:28:50 -0300] 1 1 - 192.168.0.105 Test Page - -SamsungML1640Series gacanepa 29 [18/Aug/2014:11:45:57 -0300] 1 1 - 192.168.0.105 Test Page - -这个page_log日志显示每一页被打印过的信息,只包括哪些用户发送这些打印任务,打印日期&时间,以及客户端的IPv4地址。要安装Epson喷墨和PDF打印机,我们只需重复第1-5的步骤即可,并每一次选择左边的打印队列。例如,在下图中选择PDF打印机:然而,请注意到根据CUPS-PDF 文档中,根据默认:PDF文件将会被放置在打印作业的所有者命名的子目录内。在这个案例中,打印作业的所有者不能被识别(i.e.不会存在服务器中)输出的内容被放置在匿名操作的文件中。这些默认的文件夹可以通过改变在/etc/cups/cups-pdf目录中的Out值和AnonDirName变量来修改。这里,${HOME}被扩展到用户的家目录中:Out ${HOME}/PDFAnonDirName /var/spool/cups-pdf/ANONYMOUS网络打印实例 实例 #1 从Ubuntu12.04中打印,通常在本地用gacanepa(具有相同名字存在打印机服务器上)。打印到PDF打印机之后,让我们来检查打印机服务器上的/home/gacanepa/PDF目录下的内容:root@debian:~# ls -l /home/gacanepa/PDF total 368-rw------- 1 gacanepa gacanepa 279176 Aug 18 13:49 Test_Page.pdf-rw------- 1 gacanepa gacanepa 7994 Aug 18 13:50 Untitled1.pdf-rw------- 1 gacanepa gacanepa 74911 Aug 18 14:36 Welcome_to_Conference_-_Thomas_S__Monson.pdf这个PDF文件被创建时的,权限已经设置为600(-rw-------),这意味着只有打印任务的所有者(在这个例子中是gacanepa )可以访问它们。我们可以通过修改the /etc/cups/cups-pdf.conf文件UserUMask变量的值来改变这种行为。例如,0033的umask值将可以使PDF打印者以及其它所有者拥有创建文件的权限,但是只读权限也会赋予给其它所有者。 root@debian:~# grep -i UserUMask /etc/cups/cups-pdf.conf ### Key: UserUMaskUserUMask 0033对于那些不熟悉umask(有名用户文件创建模式掩码),它作为一组可以用于控制那些为新文件创建时修改默认权限。给予特定的umask值,在计算最终文件的许可权限时,在文件基本权限(0666)和umask的单项按位补码之间进行按位布尔 AND 运算。因此,假如设置一个umask值为0033,那么新文件默认的权限将不是(0033)AND 0666 = 644的值(文件拥有者具有读/写/执行的权限,其他人拥有只读权限)。实例 #2 在Ubuntu12.04执行打印,本地登录用户为jdoe(同样的帐号名称但是服务器上是不存在的)。 root@debian:~# ls -l /var/spool/cups-pdf/ANONYMOUS total 5428-rw-rw-rw- 1 nobody nogroup 5543070 Aug 18 15:57 Linux_-_Wikipedia__the_free_encyclopedia.pdf这个PDF被创建时赋予的权限是666(-rw-rw-rw-),这意味着每个人都可以访问它们。我们可以通过编辑在/etc/cups/cups-pdf.conf文件中的AnonUMask值来改变这种行为。在这一点上,你也许会疑惑:为什么同样安装一台网络打印机,大多数(当然不是全部)当前的Linux桌面发行版都会内置一个打印到文件的功能来允许用户动态创建PDF文件?使用一台网络PDF打印机有以下好处:一个网络打印机(任何类型的)允许你直接从命令行直接打印,无需首先打开文件。在其它操作系统上安装一个网络客户端,一个PDF网络打印机备件,于是系统管理员不必再单独需要安装PDF创建者实用程序(也避免了最终用户安装这些工具存在的风险)。网络PDF打印机允许通过配置权限直接打印一个网络共享,如我们所见的例子。在Ubuntu桌面安装一个网络扫描仪 这里是通过Ubuntu桌面客户端安装和访问一台网络扫描仪的一些步骤。假设网络扫描仪服务器已经启动并运行所述here.1)让我们第一步来检查在我们的Ubuntu客户端主机上是否存在一台可用的扫描仪。没有先前的安装,你将会看到信息提示没有识别到扫描仪. $ scanimage -L2) 现在我们需要启用saned进程,用来预装Ubuntu桌面。要启用它,我们需要编辑/etc/default/saned文件,并设置RUN变量为yes:$ sudo vim /etc/default/saned # Set to yes to start sanedRUN=yes3) 让我们编辑/etc/sane.d/net.conf文件,并在扫描仪安装后添加服务器IP地址:4) 重启saned进程:$ sudo service saned restart 5) 现在让我们来看看扫描仪是否可用: 现在我们可以打开Simple Scan(或者其它扫描工具)并开始扫描文件。我们可以旋转,修剪,和保存生成的图片:总结 拥有一或多台网络打印机或扫描仪在任何办公和家庭网络中都是非常方便适用的,并同时提供了许多好处。例举如下:多用户(从不同的平台/地方)都能够向打印机发送打印作业的队列。由于硬件共享达到了节约成本和维护的作用。我希望该文可以帮助你更充分地利用这些有点。

推荐两个基于 SpringBoot 的工作流项目,很有用!

SQL 执行进展优化方法总结

白宫的大数据报告:隐私问题解决宜早不宜晚

1 sudo apt-get install vsftpd 2 sudo nano /etc/vsftpd.conf 修改如下 3 anonymous_enable=YES 允许匿名用户访问 write_enable=YES # anon_world_readable_only=YES # anon_other_write_enable=YES

七大最具影响力的大数据应用案例

2016年年内表现最为耀眼的七款JavaScript框架

Remix 对比 Next.js :一文深度解析

友情链接

滇ICP备2023000592号-9