布景

微信约束大众号推送消息夹藏“私货”

MySQL常识中的小通明-字符集和比较规矩

取完快递,缴完停车费后,,咱们常常会收到夹藏“私货”的大众号消息,补白里边充满着大量的广告类消息,往往比实践推送的有用消息还要长~

好在,微信本年针对此类现象进行了治理。不对夹藏“私货”进行批判,只聊一下“私货”里边emoji表情是怎么存储

咱们运用MySQL5.7,建一张表,专门存储emoji表情

CREATE TABLE `emoji` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  'title' varchar(120) NOT NULL DEFAULT '',
  PRIMARY KEY(id)
) ENGINE = InnoDB;

尝试刺进数据

INSERT INFO emoji(title) VALUES ('');

发现并不能成功刺进

MySQL常识中的小通明-字符集和比较规矩

数据库版别晋级,势在必行

Oracle宣布中止保护 MySQL5.7 了,截止时间是2023.10.31

MySQL常识中的小通明-字符集和比较规矩

对咱们有什么影响吗?

尽管咱们用的是5.7版别,但是运用的是RDS云服务啊,跟咱们自己服务不要紧啊~

其实不是的,Oracle不保护5.7版别了,站在云服务视点来看,存在一些问题:

  • 开源数据库存在未知安全漏洞,MySQL5.7得安全性无法保证
  • 开源数据库需恪守开源协议,依据源软件规矩的任何修正都需求履行开源义务,若自己保护MySQL5.7很可能会让自己修正的代码被迫开源

各大云厂商也陆续推出了关于MySQL5.7的保护截止时间,那么,在不久的将来,咱们行将面临的一个问题是 — MySQL的版别搬迁, 很可能是搬迁至8.0版别

没区别巨细写,查到的太多

在比较常见的含糊查询需求中,一般的处理办法是 like ‘%{key}%’ 一把梭,但一旦给含糊查询增加一个约束条件:区别巨细写,这时候会发现这一套忽然玩不转了,当咱们查找key包括a的一切数据时,会一起返回key包括A的一切数据。

除了在代码中依据巨细写过滤返回成果外,能够直接经过修正数据表的比较规矩来完成含糊查询的巨细写区别

字符调集比较规矩

咱们不常关注到字符调集比较规矩,但他们的确能帮咱们处理一些实践问题

字符集

计算机中的字符,全都会以二进制进行存储,想要存储字符串,就需求建立<字符,二进制>的映射联系。将字符映射为二进制的进程,叫做编码;将二进制数据映射为字符的进程,叫做解码

常用的字符集

  • ASCII 字符集
    • 录入128个字符,运用1个字节进行编码
  • ISO 8859-1 (latin1)字符集
    • 录入256个字符,在ASCII上,扩充了128个西欧常用字符,也能够用一个字节来编码
  • GB2312 字符集
    • 录入汉字、拉丁字母、希腊字母、日文、俄语。其间录入汉字6763个,其他文字符号682个,一起兼容ASCII字符集,运用变长编码办法:若字符在ASCII字符会集,运用1字节编码,不然采用2字节编码
  • GBK 字符集
    • 在录入字符范围上扩充了GB2312字符集,兼容GB2312
  • utf8 字符集
    • 录入地球上能想到的一切字符(不断扩充)。运用变长编码办法,编码一个字符,需求1~4个字节
    • utf8是Unicode字符集的一种编码方案,还有utf16、utf32这几种编码方案

MySQL支撑的字符集和比较规矩

将数据直接搬迁至8.0版别的实例,是否就能直接用了呢?

很可能出现因字符集问题,导致的数据问题,MySQL5.7的默许字符集为utf8,MySQL8.0的默许字符集也是utf8,但MySQL5.7的utf8,实践为utf8mb3,MySQL8.0的utf8,实践为utf8mb4,utf8mb3表明最多运用3个字节来表明一个字符,utf8mb4表明最多用4个字节表明一个字符。

这里假设MySQL5.7中创建的表都没有制定字符集,默许运用了utf8mb3,假如在MySQL8.0不指定字符集创建数据表,默许运用ut8mb4,用新建的表和MySQL5.7搬迁过来的表做相关查询,则相关字段无法走索引,执行效率受到影响。

utf8能够用1 ~ 4个字节表明一个字符,常用的字符运用1~3个字节就能够表明了,MySQL针对utf8界说了两个新的字符集概念:

  • utfmb3,用1~3个字节表明字符,在MySQL中,utf8是utfmb3的别名
  • utfmb4,用1~4个字节表明字符

回到文初的问题,假如要正常存储emoji表情,那么就需求修正对应的字符集编码

修正编码后,果然能正常写入emoji表情了

MySQL常识中的小通明-字符集和比较规矩

字符集和比较规矩操作

检查字符集

SHOW CHARSET
SHOW CHARACTER SET

MySQL常识中的小通明-字符集和比较规矩

常见的有

字符集 最大长度
ascii 1
latin1 1
gb2312 2
gbk 2
utf8 3
utf8mb4 4

检查比较规矩

SHOW COLLATION LIKE {字符集};

每种字符集,都支撑多种比较规矩,以utf8为例

mysql> SHOW COLLATION LIKE 'utf8_%';
+--------------------------+---------+-----+---------+----------+---------+
| Collation                | Charset | Id  | Default | Compiled | Sortlen |
+--------------------------+---------+-----+---------+----------+---------+
| utf8_general_ci          | utf8    |  33 | Yes     | Yes      |       1 |
| utf8_bin                 | utf8    |  83 |         | Yes      |       1 |
| utf8_unicode_ci          | utf8    | 192 |         | Yes      |       8 |
| utf8_icelandic_ci        | utf8    | 193 |         | Yes      |       8 |
| utf8_latvian_ci          | utf8    | 194 |         | Yes      |       8 |
| utf8_romanian_ci         | utf8    | 195 |         | Yes      |       8 |
| utf8_slovenian_ci        | utf8    | 196 |         | Yes      |       8 |
| utf8_polish_ci           | utf8    | 197 |         | Yes      |       8 |
| utf8_estonian_ci         | utf8    | 198 |         | Yes      |       8 |
| utf8_spanish_ci          | utf8    | 199 |         | Yes      |       8 |
| utf8_swedish_ci          | utf8    | 200 |         | Yes      |       8 |
| utf8_turkish_ci          | utf8    | 201 |         | Yes      |       8 |
| utf8_czech_ci            | utf8    | 202 |         | Yes      |       8 |
| utf8_danish_ci           | utf8    | 203 |         | Yes      |       8 |
| utf8_lithuanian_ci       | utf8    | 204 |         | Yes      |       8 |
| utf8_slovak_ci           | utf8    | 205 |         | Yes      |       8 |
| utf8_spanish2_ci         | utf8    | 206 |         | Yes      |       8 |
| utf8_roman_ci            | utf8    | 207 |         | Yes      |       8 |
| utf8_persian_ci          | utf8    | 208 |         | Yes      |       8 |
| utf8_esperanto_ci        | utf8    | 209 |         | Yes      |       8 |
| utf8_hungarian_ci        | utf8    | 210 |         | Yes      |       8 |
| utf8_sinhala_ci          | utf8    | 211 |         | Yes      |       8 |
| utf8_german2_ci          | utf8    | 212 |         | Yes      |       8 |
| utf8_croatian_ci         | utf8    | 213 |         | Yes      |       8 |
| utf8_unicode_520_ci      | utf8    | 214 |         | Yes      |       8 |
| utf8_vietnamese_ci       | utf8    | 215 |         | Yes      |       8 |
| utf8_general_mysql500_ci | utf8    | 223 |         | Yes      |       1 |
+--------------------------+---------+-----+---------+----------+---------+
27 rows in set (0.00 sec)

比较规矩规律

  • 都以字符集称号开头,用下划线分隔
  • 字符集后边,表明作用于哪种言语,比如utf8_spanish_ci作用于西班牙语,常见的utf8_general_ci是通用的规矩
  • 后缀表明重音、是否区别巨细写
后缀 英文释义 描述
_ai accent insensitive 不区别重音
_as accent sensitive 区别重音
_ci case insensitive 不区别巨细写
_cs case sensitive 区别巨细写
_bin binary 以二进制办法比较

utf8默许的比较规矩utf8_general_ci便是不区别巨细写的

咱们在含糊查找时,假如想区别巨细写,又不想修正代码,就能够修正一下数据库对应列的比较规矩

了解数据库字段区别巨细写了,数据库表名、库名怎么区别巨细写呢?

比如常用的定时使命框架Quartz,需求建一堆的初始数据表,copy下来的建表句子表名全都是大写的,假如巨细写灵敏,那么SQL里Select的小写表名就找不到

经过lower_case_table_names数据库参数,决定数据表是否巨细写灵敏,参数有3个取值

  • 0 巨细写灵敏 (LInux默许)按照巨细写生成数据库文件,命名为AbC,则生成AbC.frm文件
  • 1 巨细写不灵敏 (Windows默许)数据库表转换为小写存储,SQL表名也会转成小写查询
  • 2 巨细写不灵敏 (OS X默许)数据库表原样保存,SQL句子将库名转成小写

字符集和比较规矩等级

在MySQL中,字符集和比较规矩,分成几个等级:服务器等级 -> 数据库等级 -> 表等级 -> 列等级,假如没有显示标识,则承继上一等级的字符集和比较规矩

服务器等级

MySQL供给了两个体系变量来表明服务器等级的字符集和比较规矩,假如要修正这两个变量,需求重启server

  • character_set_server
  • collation_server

数据库等级

创库时设置、修正已有库的字符串和比较规矩,假如不设置,则默许运用服务器等级的字符集和比较规矩

CREATE DATABASE test
  CHARACTER SET {字符集称号}
  COLLATE {比较规矩称号}
ALTER DATABASE test
  CHARACTER SET {字符集称号}
  COLLATE {比较规矩称号}

检查数据库的字符集和比较规矩

USE {DATABASE名};
SHOW VARIABLES LIKE 'character_set_database'SHOW VARIABLES LIKE 'collation_database'

表等级

创表时设置、修正已有表的字符串和比较规矩,假如不设置,则默许运用数据库等级的字符集和比较规矩

CREATE TABLE {表名} (列信息)
  CHARACTER SET {字符集称号}
  COLLATE {比较规矩称号}
ALTER TABLE {表名}
  CHARACTER SET {字符集称号}
  COLLATE {比较规矩称号}

列等级

同一张表中,不同的列,能够有不同的字符集和比较规矩,若没有单独设置,则默许运用表的字符集和比较规矩

CREATE TABLE {表名} (
  {列名} {字符串类型} CHARACTER SET utf8 COLLATE utf8_general_ci,
  其他列信息...
);

能够单独修正某一列的字符集和比较规矩,假如修正前的字符,无法用修正后的字符集表明,会出错(ex:utf8存汉字,转换为ascii会报错,ascii只支撑128个字符表明)

ALTER TABLE {表名} MODIFY col VARCHAR(10) CHARATER SET utf8 COLLATE gbk_chinese)ci;

通讯中的字符集

客户端和服务端通讯进程中,涉及到编码转换

  • character_set_client
    • 服务端以为客户端运用character_set_client编码,所以客户端编码需求和设置的character_set_client编码保持一致
  • character_set_results
    • 服务端将成果集用character_set_results编码后发送回客户端
  • character_set_connection
    • 服务端的一种中间态编码,用来将character_set_client转为character_set_results

大部分情况下咱们只需求用utf8编码一把梭,不需求关注MySQL是怎么进行编码转换的,MySQL也供给了一把梭的办法,统一设置三个字符变量的值

SET NAMES {字符集}