1、前言
对于从事互联网开发的同窗来讲,mysql可谓是再熟悉不过的了。不管是DBA、开发或测试,基本上每天要跟它打交道,不少同窗可能已经身经百战了。可是,笔者遇到过的这些坑不知道大家都经历过没?mysql
2、有符号和无符号
之前咱们公司在项目开发之初制定开发规范时,对mysql的int类型字段定义成有符号,仍是无符号问题专门讨论过。sql
观点一:数据库
对于可以肯定里面存的值必定是正数的字段,定义成UNSIGNED无符号的,能够节省一半的存储空间。建立无符号字段的语句以下:函数
create table test_unsigned(a int UNSIGNED, b int UNSIGNED);
观点二:测试
建议都定义成有符号的,使用起来比较简单,mysql默认int类型就是有符号的,建立有符号字段的语句以下:编码
create table test_signed(a int); insert into test_signed values(-1);
执行结果:spa
在字段a中插入-1,咱们看到是能够操做成功的。server
这两个方案,通过咱们激烈讨论以后,选择了使用有符号定义int类型字段。为何呢?blog
create table test_unsigned(a int UNSIGNED, b int UNSIGNED); insert into test_unsigned values(1,2);
先建立test_unsigned表,里面包含两个无符号字段a和b,再插入一条数据a=1,b=2排序
select b - a from test_unsigned;
没有问题,返回1
可是若是sql改为这样:
select a - b from test_unsigned;
执行结果:
报错了。。。
因此,在使用无符号字段时,千万要注意字段相减出现负数的坑,建议仍是使用有符号字段,避免没必要要的问题。
3、自动增加
建过表的同窗都知道,对于表的主键能够定义成自动增加的,这样一来,就能够交给数据库本身生成主键值,而无需在代码中指定,并且生成的值是递增的。通常状况下,建立表的语句以下:
create table test_auto_increment (a int auto_increment primary key);
但若是改为这样的会怎样?
create table test_auto_increment (a int auto_increment);
执行结果:
报错了。。。
截图中没有所有显示出来,完整的提示语是这样的:
1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key, Time: 0.006000
意思是自动增加字段,必须被定义成key,因此咱们须要加上primary key。
此外,还有一个有趣的实验:
insert into test_auto_increment(a) values (null),(50),(null),(8),(null);
你们猜猜执行结果会是什么样的?
第一个null插入1,而后按真实的数字大小排序后插入,后面两个null,是在最大的数字上面加1。
再看看这条sql主键中插入负数,能执行成功吗?
insert into test_auto_increment values(-3);
答案是能够,主键能够插入负数。
还有这条sql呢,主键中插入0?
insert into test_auto_increment values(0);
执行结果:
也能够执行成功,可是没有插入数据
4、字段长度
咱们在建立表的时候,给字段定义完类型以后,紧接着须要指定字段的长度,好比:varchar(20),biginit(20)等。那么问题来了,varchar表明的是字节长度,仍是字符长度呢?
create table test_varchar(a varchar(20)); insert into test_varchar values('苏三说技术'); select length(a),CHARACTER_LENGTH(a) from test_varchar;
执行后的结果:
咱们看到中文的5个字length函数统计后长度为15,表明占用了15个字节,而使用charcter_length函数统计长度是5,表明有5个字符。因此varchar表明的是字符长度,由于有些复杂的字符或者中文,一个字节表示不了,utf8编码格式的一个中文汉字占用3个字节。不一样的数据库编码格式,占用不一样的字节数对照表以下:
mysql除了varchar和char是表明字符长度以外,其他的类型都是表明字节长度。
int(n) 这个n表示什么意思呢?从一个列子出发:
create table test_bigint (a bigint(4) ZEROFILL); insert into test_bigint values(1); insert into test_bigint values(123456); select * from test_bigint;
ZEROFILL表示长度不够填充0
执行结果:
mysql经常使用数字类型字段占用字节数对照表:
从表中能够看出bigint实际长度是8个字节,可是咱们定义的a显示4个字节,因此在不满4个字节时前面填充0。满了4个字节时,按照实际的长度显示,好比:123456。可是,须要注意的是,有些mysql客户端即便满了4个字节,也可能只显示4个字节的内容,好比显示:1234。
因此bigint(4),这里的4表示显示的长度为4个字节,实际长度仍是8个字节。
5、忽略大小写
咱们知道在英文字母中有大小写问题,好比:a 和 A 是同样的吗?咱们认为确定是不同的,可是数据库是如何处理的呢?
create table test_a(a varchar(20)); insert into test_a values('a'); insert into test_a values('A'); select * from test_a where a = 'a';
执行结果是什么呢?
本觉得只会返回a,可是实际上把A也返回了,这是为何呢?
该表默认的Collation是utf8_general_ci,这种Collation会忽略大小写,因此才会出现查询小写字母a的值,意外把大写字母A的值也查询出来了。
那么若是咱们只想查询出小写a的值该怎么办?先看看mysql支持哪些Collation?
show collation;
从上图中咱们能够找到utf8_bin,这个表示二进制格式的数据,咱们设置成种类型的试试。
修改一下字段类型
ALTER TABLE test_a MODIFY COLUMN a VARCHAR(20) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL;
再查看一下数据
select * from test_a where a = 'a';
执行结果:
果真,结果对了。
6、特殊字符
笔者以前作项目的时候,提供过一个留言的功能,结果客户端用户输入了一个emoji表情,直接致使接口报错了。
最后定位缘由是因为当时数据库和表的字符编码都是用的utf8,mysql的utf8编码的一个字符最多3个字节,可是一个emoji表情为4个字节,因此utf8不支持存储emoji表情。
该如何解决这个问题呢?
将字符编码改为utf8mb4,utf8mb4最多能有4字节,不过,在mysql5.5.3或更高的版本才支持。
在mysql 的配置文件 my.cnf 或 my.ini 配置文件中修改以下:
[client] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_general_ci
重启MySQL,而后使用如下命令查看编码,应该所有为utf8mb4,这是修改整个数据库的编码方式。
SHOW VARIABLES WHERE Variable_name LIKE 'character_set_%' OR Variable_name LIKE 'collation%';ji
结果为:
也能够单独修改某张表的编码方式:
alter table test_a convert to character set utf8mb4 collate utf8mb4_bin;
以及修改某个字段的编码方式:
ALTER TABLE test_a CHANGE a a VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
此外,建议同窗们在建立数据库和表的时候字符编码都定义成utf8mb4,避免一些没必要要的问题。