MySQL杂谈-自增主键、有无符号、字符比较、时区影响

一、整数值的那些事

1. 我常用整数类型

类型 大小(byte) 范围(有符号) 范围(无符号) 用途
TINYINT 1 (-128,127) (0,255) 小整数值 或 true/false
INT 4 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 8 (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
关键点:
  • 在MySQL中的 true 和 false ,就是用 1 和 0 来表示。
  • 无符号整数,在正数值的表示范围是原来的两倍,但不能表示负数。

2. 整数值有无符号的坑

关于INT和BIGINT,有符号和无符号其实还是有一些比较有趣的故事。

首先创建一张数据表
create table test_unsigned ( 
a int UNSIGNED,
b int UNSIGNED
);

在这个数据表中,a和b都是无符号的整数,我尝试新增进入这张表两个数据。

insert into test_unsigned values (1,2);
insert into test_unsigned values (1,1);

此时数据表中有两行数据,1,1 和 1,2。

那么我们可以预测一下下列的sql的执行结果是什么?
mysql> select b-a from test_unsigned;
+------+
| b-a  |
+------+
|    1 |
|    0 |
+------+
2 rows in set (0.00 sec)

结果显示是正常的,1-1是0,2-1是1.也就是说无符号的字段是可以表示0的。

在看一个SQL,预测一下执行结果是什么?
mysql> select a-b from test_unsigned;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`mall`.`test_unsigned`.`a` - `mall`.`test_unsigned`.`b`)'

报错了,由于a和b是无符号的值,如果结果为负数,超出了其表达的范围就会报错。

整数值的有无符号结论:

无符号:字段值只能出现正数不能出现负数可以出现0,且正数的表示范围会 * 2(多了一位)。
有符号:可以出现负数,正常的表示范围。
故我们在选用无符号的时候需要考虑到这个问题。

3.整数值的宽度限制

日常开发中我们通常会看到如下语句,声明int(n),int(n) 中的 n 仅仅指的是显示宽度。且限制这个字节后如果不跟上ZEROFILL其实是没有意义的。

create table test_int_n(
a int(4) ZEROFILL
);

尝试向表中新增两条数据.

insert into test_int_n values (1);
insert into test_int_n values (11);
insert into test_int_n values (1111);
insert into test_int_n values (12345);
查询一下该表的全部数据吧
mysql> select * from test_int_n;
+-------+
| a     |
+-------+
| 12345 |
|  0001 |
|  0011 |
|  1111 |
+-------+
4 rows in set (0.00 sec)

不满足4个的就补0,满足4个的就正常显示。

被设置ZEROFILL的字段默认是无符号的
mysql> insert into test_int_n values (-1);
ERROR 1264 (22003): Out of range value for column 'a' at row 1

该案例即可证明,该字段无法表示负值。

4.趣味的自增主键

率先创建一张自增ID的数据表,并插入第一组数据。
create table test_auto_increment(
a int auto_increment primary key
);

尝试新增第一组数据,空和非空不等。

mysql> insert into test_auto_increment values (null),(5),(null),(15),(null),(10),(null);
Query OK, 7 rows affected (0.01 sec)
Records: 7  Duplicates: 0  Warnings: 0
查询第一组数据的插入结果
mysql> select * from test_auto_increment;
+----+
| a  |
+----+
|  1 |
|  5 |
|  6 |
| 10 |
| 15 |
| 16 |
| 17 |
+----+
7 rows in set (0.00 sec)

可以看出,为null的就走自增了,而我们指定的主键会迫使主键自增序列同步,也就是自增序列为当前字段的最大值。若下一个值为null就从字段最大值开始向上递增。

插入第二组数据并查看结果

插入 -1 和 0 值。

mysql> insert into test_auto_increment values (-1),(0);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

查看结果并对比之前的结果。

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  5 |
|  6 |
| 10 |
| 15 |
| 16 |
| 17 |
| 19 |
+----+
9 rows in set (0.00 sec)

-1值可以正常的插入进去,该字段并没有标明是无符号的,所以可以表示负值。
****关键在于 “0” ,自增主键为“0”时并没有真正意义上的插入“0”,而是走了自增序列的下一个值,变成了19.****
很奇怪,虽然不明白为什么,这确实是一个点,以前开发过程中并没发现这个事情。

二、字符类型的那些事

1.'a'是否等于'A'

执行查询语句查看结果
mysql> select 'a' = 'A'; 
+-----------+
| 'a' = 'A' |
+-----------+
|         1 |
+-----------+
1 row in set (0.00 sec)

可以看到,查询结果是'1',目前的情况下A是等于a的。

建立数据表再次验证这个问题

创建数据表并新增两条数据。

create table test_ci (
a varchar(10),key(a)
);
insert into test_ci values ('a'),('A');
mysql> select * from test_ci;
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

数据已经填充进去了,再次执行验证的查询SQL。

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

结果是 a 依旧等于 A ,这个究竟是什么问题?

排序规则,bin 二进制区分大小写,ci(case insensitive) 忽略大小写。

修改排序规则再次验证

mysql> set names utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)

mysql> select 'a' = 'A'; 
+-----------+
| 'a' = 'A' |
+-----------+
|         0 |
+-----------+
1 row in set (0.00 sec)

更改排序规则为二进制之后就会区分大小写了。

三、时间类型的时区

1.timestamp 和 datetime

建立数据表新增数据进行测试
create table test_time (
a timestamp,
b datetime
);
insert into test_time  values (now(),now());

查询结果

mysql> select * from test_time;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2020-07-08 10:46:56 | 2020-07-08 10:46:56 |
+---------------------+---------------------+
1 row in set (0.00 sec)

可以看到,新增进去的时间不论是时间戳还是datetime都是可以精确表示当前时间的。
执行完修改时区的语句后,这个查询结果就会变了。

mysql> set time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_time;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2020-07-08 02:46:56 | 2020-07-08 10:46:56 |
+---------------------+---------------------+
1 row in set (0.00 sec)

时间戳受到时区的影响,查询出来的结果发生了改变,但是datetime并没有发生改变。
MySQL默认时区为东八区, default-time-zone='+08:00' 。
所以在选用时间类型的时候需要注意到这些内容。

时区修改

****永久有效方法****
修改 my.cnf 文件,加入如下2行:

# 数据表默认时区,即设置MySQL默认时区为东八区。
default-time-zone='+08:00'          

****仅当前会话有效方法****
并不是每个时候我们都需要一致的时区,如果要在当前回话中设置独特的时区,
可以进入MySQL命令行,用命令设置当前回话的时区:
SET time_zone = "+08:00";

2.date 和 datetime 的区别

区别就很简单,一句话描述,date只能表示日期 yyyy-MM-dd。datetime却可以表示精确的时间,仅此而已。

四、总结

关于数据类型在使用的时候有很多需要注意的地方,可能有一些我还没有通过什么渠道去发现,但是在使用的过程中,但凡可以考虑到的都尽可能的去考虑一下,避免因为这些细小的问题影响到自己开发的软件的正确性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342