如何从MySQL数据类型中Get到库表设计技能

很多时候,我们开发应用系统,底层的数据库表结构都需要开发人员亲自设计,设计的合理与否,关乎着整个系统的稳定性和运行速率,系统上线后再频繁地对后端数据库表结构进行修改更是大忌。所以我们需要更多地储备数据库层面的知识和技能,以便最初就能设计好表结构。

本篇基于MySQL数据库,尽可能详细地为大家解析MySQL基本的数据类型和设计库表结构时应注意的点。

目录

  • 整数类型
  • 实数类型
  • 字符串类型
    • 一、VARCHAR类型
    • 二、CHAR类型
    • 三、BLOB和TEXT类型
    • 四、枚举
  • 日期和时间类型
  • 位数据类型
  • 总结

整数类型:

MySQL整数类型有5个:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT

整数类型 存储空间(位) 存储值范围 范围计算公式
TINYINT 8(1字节) -128 ~ 127 -2^{8-1} 到 2^{8-1}-1
SMALLINT 16(2字节) -32768 ~ 32767 -2^{16-1} 到 2^{16-1}-1
MEDIUMINT 24(3字节) -8388608 ~ 8388607 -2^{24-1} 到 2^{24-1}-1
INT 32(4字节) -2147483648 ~ 2147483647 -2^{32-1} 到 2^{32-1}-1
BIGINT 64(8字节) -(9.223372e+18) ~ 9.223372e+18 -2^{64-1} 到 2^{64-1}-1

范围计算公式为:-2^{N-1} 到 2^{N-1}-1

整数类型有可选的UNSIGNED属性:表示非负值,可使正数的范围扩大一倍,例如:TINYINT的存储范围是:-128 ~ 127,TINYINT UNSIGNED的存储范围是:0 ~ 255。

【疑问】:
定义数据库表字段为整数类型,例如INT,那么INT(1),INT(11),INT(20)...等等,有什么意义和区别吗?应该怎么定义?

【解答】:
定义数据库表字段时,为整数类型指定宽度,例如INT(11),INT(20),对大多数应用没有意义,不会限制所对应存储值范围, 对于存储和计算来说,INT(11)和INT(20)是相同的,没有区别。

INT(1),INT(11),INT(20)...存储有符号范围始终都是:-2147483648 ~ 2147483647,无符号范围:0 ~ 4294967295
TINYINT(1),TINYINT(2),TINYINT(4)...存储有符号范围始终都是:-128 ~ 127,无符号范围:0 ~ 255

那指定整数类型宽度用来干什么呢?如 ITN(4)

只是一些MySQL客户端工具用来显示字符的个数。

举例:如下goods表结构


desc goods

如果num字段(或type字段)存储的值的字符数超过了所定义的宽度4,那么该值会显示全吗?


字段值字符数超过指定类型宽度

一般用法是:指定整数类型宽度的同时,定义该字段Zero Fill属性(意思是达不到指定宽度时用0填充)

类型宽度+zerofill

那么在设计数据库表字段,并定义为整数类型时,应注意:【重点,敲黑板】

  1. 一般不用指定整数类型宽度,如ITN(20),TINYINT(2)...等,除非设定Zero Fill属性,用来填充字符个数。
  2. 字段不会出现负值时,将其设定为unsigned,能扩大正数的存储范围,同时也能免去负值带来的干扰。
  3. 整型比字符操作代价更低,因为字符集和校对规则(排序规则)使字符比较比整型比较更复杂。所以定义字段类型时,先考虑整型。
  4. 表的标识列最好选择整数类型,因为很快并且可以使用AUTO_INCREMENT(自增)。
  5. 阿里巴巴Java开发手册中,建表规约 - 第9条,对设计数据库表强制要求如下:


    阿里开发-建表规约-9

实数类型:

实数是带有小数部分的数字。

MySQL的实数类型有3个:FLOAT,DOUBLE,DECIMAL

对比如下:

实数类型 存储空间(字节) 数值计算 使用
FLOAT 4字节 CPU支持原生浮点计算
因此使用PC标准的浮点运算进行近似计算
单精度,存小数时存在精度损失
DOUBLE 8字节 CPU支持原生浮点计算
因此使用PC标准的浮点运算进行近似计算
双精度(比单的精度更高,范围更大)
存小数时也存在精度损失
DECIMAL 65个数字
(MySQL>=5.0版本)
CPU不支持对DECIMAL直接计算
MySQL(>=5.0版本)服务器自己实现了DECIMAL的高精度计算
对小数进行精确计算时使用,如财务数据

说明:DECIMAL比DOUBLE,FLOAT存储空间大,存储值范围大,精度高,但是他俩比DECIMAL计算更快(FLOAT/DOUBLE使用CPU原生浮点运算,DECIMAL使用MySQL(>=5.0版本)自身实现的DECIMAL高精度计算)。

那么在设计数据库表字段,并定义为实数类型时,应注意:【重点,敲黑板】

  1. 尽量只在只在对小数进行精确计算时,使用DECIMAL类型,例如财务数据。
  2. 只指定数据类型,不指定精度(MySQL中FLOAT/DOUBLE/DECIMAL都可以指定精度,但会影响列的空间消耗)。
  3. 使用DECIMAL存储,但数据量很大(上千万条或更多),可以考虑使用BIGINT代替DECIMAL,把小数乘以相应倍数存在BIGINT中,这样可以同时避免:浮点存储计算不精确和DECIMAL精确计算代价高的问题。
  4. 使用DECIMAL存储,但存储的数据范围超过了DECIMAL的范围,建议将数据拆成整数和小数分开存储。
  5. 阿里Java开发手册,建表规约 - 第6条,对设计数据库表强制要求如下:


    阿里开发-建表规约-6

字符串类型

一、VARCHAR 类型

关于VARCHAR类型我会从以下三个方面详细解析:

  • 存储空间
  • 性能
  • 库表设计注意点

【存储空间】

VARCHAR类型是最常见的字符串数据类型,用于存储可变长字符串,一般比定长类型更节省空间,原因:VARCHAR存储时仅使用必要的空间,越短的字符串使用越少的空间。

定义库表的字段类型时,VARCHAR(100)表示什么?

VARCHAR(100)表示:能存储100个字符,注意字符数是100个,不管你存储的是汉字,符号,字母等等,它的总个数不能超过100个。

VARCHAR(100)中的 100 不表示存储空间的大小,那么存储空间大小怎么计算呢?

<1> 首先VARCHAR需要使用 1 或 2 个额外字节记录字符串的长度,这里的字符串长度是指占用的空间大小,单位是字节。
    如果存储的数据最大长度(空间大小) <= 255字节,则只额外使用 1 个字节记录长度(1个字节8位最大表示的无符号数就是255),
    否则使用 2 个字节记录。
    
<2> 存储的数据是多大字节?这就跟我们具体存什么东西以及编码相关了,比如:
    utf-8编码(小于5.5.3版本):
        存汉字:一个汉字 = 3个字节
        存英文:一个字母 = 1个字节
    gbk编码:
        存汉字:一个汉字 = 2个字节
        存英文:一个字母 = 1个字节
    utf8bm4字符集(大于5.5.3版本,注意是字符集,后面详细讨论):
        存普通常用汉字:一个汉字 = 3个字节  (普通汉字:包含在Basic Multiling Plane(BMP)字符中的汉字)
        不常用汉字:一个汉字 = 4个字节
        常用的表情字符emoji:一个表情字符emoji = 4个字节
        存英文:一个字母 = 1个字节

关于MySQL的utf8和utf8bm4之间的爱恨情仇,我会用一遍文章为大家尽可能详细的解析,请关注,这里只简单介绍:

MySQL在5.5.3版本之前使用uft8字符集,MySQL的 'utf8' 实际上不是真正的UTF-8。(可认为是MySQL的一个BUG)

标准的 UTF-8 字符集编码可以用 1 ~ 4 个字节去编码 21 位字符,几乎包含了世界上所能看到的语言了,但是MySQL的'utf8'支持的字符最大长度是 3 个字节,而标准的 UTF-8 >支持的字符最大长度是 4 个字节。

也就是说:MySQL的'utf8'只支持到了标准的 UTF-8 字符集中的部分,即基本多文本平面(Basic Multiling Plane(BMP)),包含了控制符,拉丁文,中,日,韩等绝大多数国际字符,但并不是所有,不支持:手机端常用的表情字符emoji和一些不常用的汉字,这些需要4个字节才能编码出来。

在2010年,MySQL在5.5.3版本后增加了utf8mb4 字符编码,mb4:most bytes 4(最多4字节),用来兼容之前MySQL-'utf8'不支持的四字节字符,是它的超集。

现在MySQL版本都到8以上了,所以一般在设计数据库表时,默认都使用utf8mb4字符集

实战举例:【实战很重要,敲黑板~】

<1> 基于命令行(黑窗口)的MySQL客户端

先查数据库版本:看数据库版本号基本就知道设计库表时,默认使用的字符集了


查数据库版本

查一下使用数据库的各个字符集设置:可以看出客户端来源数据和查询结果的字符集都为gbk,即字符长度:一个汉字 = 2字节,一个英文字母 = 1字节


查使用数据库字符集设置

验证一下:
select LENGTH('XXX'); -- 返回字符串'XXX'的存储长度,以字节为单位。
select CHAR_LENGTH('XXX'); -- 返回字符串'XXX'的字符数,即'XXX'含了多少个汉字,字母,符号等等,加起来共多少个字符。
select CHARACTER_LENGTH('XXX'); -- 返回字符串'XXX'的字符数。
查字符串存储长度

查字符串字符数

以school表为例:表的默认字符集和各个列的字符集都是utf8bm4,headmaster(校长)列数据类型为varchar(20),最多存储字符数是20个,存储占空间长度知道一下就行。

查school表DDL

school表各个列字符集

school表数据

<2> MySQL Workbench客户端


数据库字符集

字符串存储空间长度

【性能】

VARCHAR节省了存储空间,对性能有帮助。

update操作时可能使行变得比原来更长,因为行是变长的,这就导致需要做额外工作,则影响性能。

如果一个行占用的空间增长,且在页内没有更多的空间可以存储:
InnoDB:需要分裂页来使行可以放进页内
MyISAM:将行拆成不同的片段存储

【库表设计注意点】

  1. 一般情况下,数据库的表/字段,请使用utf8bm4编码的字符集。
  2. 字符串列的最大长度比平均长度大很多,列更新很少,适合用VARCHAR类型
  3. 阿里Java开发手册,建表规约 - 第8条,对设计数据库表强制要求如下:


    阿里开发-建表规约-8

二、CHAR 类型

我们也从以下三个方面解析:

  • 存储空间
  • 性能
  • 库表设计注意点

【存储空间】

记住两点即可:

<1> CHAR类型是定长的,CHAR(10)表示可以存储10个字符,MySQL根据定义的字符数分配足够的存储空间。

对比一下CHAR(1) 与 VARCHAR(1) 存储空间: 
存储单字节字符(如一个英文字母):
CHAR(1) : 1个字节
VARCHAR(1) : 1个字节 + 额外记录长度(占用空间大小)的1字节 = 2字节

<2> 存储CHAR值时,MySQL会删除所有的末尾空格,不会删除前面和中间的空格;存储VARCHAR值时(MySQL>=5.0版本),则会保留末尾空格。

举例:定义school表的code(学校代号)字段为CHAR(10)


desc school

为“西安电子科技大学”和“明尼苏达大学双城分校”分别设定code值:

update school set code = '  985_0011' where name = '西安电子科技大学'; (code前面有两个空格)
update school set code = '010_0039    ' where name = '明尼苏达大学双城分校'; (code末尾有四个空格)
char末尾空格被删掉

对比看一下VARCHAR(10):(注意:MySQL>=5.0版本时VARCHAR会保留末尾空格,之前版本也会删除末尾空格)

create table v_test(v_col varchar(10));
insert into v_test(v_col) values('string1'), ('  string2'), ('string3  '); (string2前面有两个空格,string3末尾有两个空格)
varchar保留末尾空格

【性能】

非常短的列:CHAR 比 VARCHAR 在存储空间上更有效率。

经常变更的列:CHAR 不易产生碎片,比 VARCHAR 更好。

【库表设计注意点】

很短的字符串,或者所有字符串都接近同一个长度(如密码的MD5值是定长),适合定义为CHAR类型。

阿里Java开发手册,建表规约 - 第7条,对设计数据库表强制要求如下:


阿里开发-建表规约-7

三、BLOB 和 TEXT 类型

BLOB 和 TEXT 都是用来存储很大的数据,BLOB采用二进制存储,TEXT采用字符方式存储。

MySQL把每个 BLOB 和 TEXT值当作一个独立的对象处理,存储引擎在存储时通常会做特殊处理。

怎么个特殊处理呢?
当BLOB和TEXT值太大时,InnoDB会使用专门的“外部”存储区域来进行存储:每个值在表行内用1 ~ 4字节存储一个指针,指向外部存储区域存储的实际值。

对比:

BLOB: 存二进制数据,没有排序规则或字符集
TEXT:存字符串,有排序规则和字符集,只对每列的最前max_sort_length字节而不是整个字符串做排序。
若只需要排序前面一小部分字符,可以减小max_sort_length的配置,或使用ORDER BY SUSTRING(column, length)。
max_sort_length

四、枚举

MySQL中使用ENUM('xxx1','xxx2','xxx3')定义字段为枚举列。

我们从以下四个方面解析:

  • 存储结构
  • 存储空间
  • 排序
  • 添加/删除/更改枚举字符串

【存储结构】

枚举列是把不重复的字符串存储成一个预定义的集合,如ENUM('fish','dog','pig'),在MySQL内部会将每个值在列表中的位置保存为整数,并在表的.frm文件中保存 “数字 - 字符串” 映射关系的 “查找表”。

举例:

新建表:create table enum_test(e_col ENUM('fish','dog','pig') NOT NULL); (e_col列为枚举)
插入数据:insert into enum_test(e_col) values('fish'),('dog'),('pig'); (只能插枚举列表中的值,否则报错)
ENUM存储结构

【存储空间】

MySQL在存储枚举时非常紧凑,根据列表值的数量(注意是数量)压缩到一个或两个字节中。

【排序】

枚举字段按照内部存储的整数而不是定义的字符串进行排序。

枚举排序

如果需要按照定义的字符串排序,怎么做呢? 使用FIELD()函数
使用field函数指定排序

所以,建议在定义枚举列表值时就按照字母的顺序。

【添加/删除/更改枚举字符串】

必须使用ALTER TABLE命令:

alter table enum_test change column e_col e_col ENUM('fish', 'dog') NOT NULL;
alter table enum_test change column e_col e_col ENUM('fish', 'dog', 'monkey') NOT NULL;
添加/删除/更改枚举字符串

日期和时间类型

MySQL提供了两种相似的日期类型:DATETIME 和 TIMESTAMP

我们从以下三个方面对比这两种日期类型:

  • 时间范围
  • 存储空间
  • 显示格式

【时间范围】

DATETIME:能保存大范围的值,从1001年到9999年,精度为秒。

TIMESTAMP:保存了从1970年1月1日零点(格林尼治标准时间)以来的秒数,它和UNIX时间戳相同,只能表示的范围是:1970年 ~ 2038年。

【存储空间】

DATETIME:把日期和时间封装到格式为YYYYMMDDHHMMSS的整数中,与时区无关,使用8个字节的存储空间。

TIMESTAMP:使用4字节的存储空间。

【显示格式】

DATETIME:2008-01-16 22:37:08(MySQL默认情况下)

TIMESTAMP:2008-01-16 22:37:08(MySQL>=4.1版本,按照DATETIME方式格式化),显示的值依赖时区。

怎么个依赖时区呢?
举例:TIMESTAMP类型字段存储值为0,则在美国东部时区显示为:1969-12-31 19:00:00(不是1970-01-01 00:00:00),因为与格林尼治时间差了5个小时。

如果在多个时区存储或访问数据,TIMESTAMP提供的值与时区有关系,DATETIME则保留文本表示的日期和时间,跟时区无关,所以它们很不一样。

那么在设计数据库表字段,并定义为日期和时间类型时,应注意:【重点,敲黑板~】

  1. 除特殊之外,一般情况尽量使用TIMESTAMP,因为比DATETIME空间效率更高。
  2. 一般不要把Unix时间戳存储为整数值,不方便处理。
  3. MySQL能存储的最小时间粒度为秒,如果要存储比秒更小粒度的日期和时间,可以使用BIGINT类型存储微秒级别的时间戳,或者使用DOUBLE存储秒之后的小数部分。
  4. 创建表时一般增加create_time(创建时间)字段,update_time(更新时间)字段,根据操作自动填入当前时间,如下:
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

位数据类型

MySQL有少数几种存储类型使用紧凑的位存储数据,这些位类型,不管从底层存储格式和处理方式上,都是字符串类型。

我们以 BIT 和 SET 为例,来解析位数据类型。

【存储结构】

BIT

BIT(1):存储1个位,BIT(2):存储2个位,BIT列最大长度是:64个位。

存储二进制值 b'00111001'(前面加b表示二进制,必须要有)
查询返回值是:ASCII码为该二进制数值所对应的字符'9'('00111001'表示数是57,在ASCII码中,编码为57的字符'9',即查到的就是字符'9')
数字上下文场景中查询返回值是:数字57,即ASCII码的编码数字
存储空间:InnoDB引擎使用能够存储下的最小整数类型来存放,如:8位bit的话,用TINYTINT就能存放下,所以存储空间为1字节。
BIT存储

SET

SET:MySQL内部是以一系列打包的位的集合来表示,每个位(bit)或者SET元素代表一个值。

举例:
创建一个权限访问控制表acl:create table acl(perms SET('READ', 'WRITE', 'DELETE') NOT NULL);
其中把权限'READ', 'WRITE', 'DELETE'打包成一个位的集合SET,每个SET元素代表一个值:
'READ'   -- 00000001(二进制位表示) -- 1
'WRITE'  -- 00000010(二进制位表示) -- 2
'DELETE' -- 00000100(二进制位表示) -- 4

MySQL在列定义里存储位到值的映射关系,即:"bit位值 - 元素字符串",与枚举ENUM相似。

我们acl表插入权限值:insert into acl(perms) values('READ'),('WRITE'),('DELETE'),('READ,DELETE'); 看一下查询acl表数据:
(注意:可以在一列中存储多个SET元素)
SET存储

【库表设计注意点】

  1. 谨慎使用BIT类型,最好避免使用。
  2. SET类型虽有效利用了存储空间,但改变列定义需要ALTER TABLE,代价较高,可以考虑使用一个整数包装一系列的位,如:TINYINT包装8个位。

总结

对库表设计注意点,做个整体汇总20条:

  1. 表名不使用复数名词(表名应该仅仅表示表里的实体内容,不应表示实体数量)(阿里规范-建表规约-3) 。
  2. 表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字(阿里-建表规约-2)。
正例:aliyun_admin,rdc_config,level3_name
反例:AliyunAdmin,rdcConfig,level_3_name
  1. 尽量避免 NULL,因为可为 NULL 的列会使用更多的存储空间,而且索引,索引统计和值比较都更复杂。
  2. 尽量使用可以正确存储数据的最小数据类型,因为占用更少的磁盘、内存和CPU缓存,所以更快。
  3. 整型比字符串操作代价更低,因为字符集和校对规则(排序规则)使字符比较比整型比较更复杂。
IPV4地址实际上是32位无符号整数,不是字符串,所以应该用无符号整数(INT UNSIGNED)存储IP地址
MySQL提供函数:INET_ATON(), INET_NTOA(), 在字符串表示和整数表示之间转换。
说明:用小数点将地址分为4段的表示法只是让人们阅读容易。
  1. 一个表中不要有太多的列,因为InnoDB在MySQL服务器层和存储引擎层之间会将列转换成行数据结构,依赖列的数量。
  2. 不要关联太多表,单个查询最好在12个表以内做关联。(MySQL限制了每个关联操作最多只能有61张表)
  3. 一般不要指定整数类型宽度,如ITN(20),TINYINT(2)等,除非设定Zero Fill属性,用来填充字符个数。
  4. 整型字段不会出现负值时,将其设定为UNSIGNED,能扩大正数存储范围,同时也能免去负值的干扰。
  5. 尽量只在对小数进行精确计算时,使用DECIMAL类型,如财务数据。(float和double在存储时,存在精度损失问题)
  6. 使用DECIMAL存储,数据量大时(上千万条或更多),考虑把小数乘以相应倍数,使用BIGINT存储;存储数据超范围时,考虑把数据拆成整数和小数分开存储。
  7. 一般情况下,数据库的表/字段,请使用utf8bm4编码的字符集。
  8. VARCHAR是可变字符串,不预先分配存储空间,长度不要超过5000,如果超过,定义字段类型为TEXT,独立出一张表,用主键对应关联。(阿里-建表规约-8)
  9. 很短的字符串,或者所有字符串都接近同一个长度,如密码的MD5值是定长,考虑使用CHAR类型。
  10. 不要把Unix时间戳存储为整数值,不方便处理。
  11. 一般情况尽量使用TIMESTAMP,因为比DATETIME空间效率高,
  12. 创建表时一般增加create_time(创建时间)字段,update_time(更新时间)字段,根据操作自动填入当前时间,如下:
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  1. MySQL能存储的最小时间粒度为秒,如果要存储比秒更小粒度的日期和时间,可以使用BIGINT类型存储微秒级别的时间戳,或者使用DOUBLE存储秒之后的小数部分。
  2. 谨慎使用BIT类型,最好避免使用。
  3. 选择表的列标识符时,整数类型是最好的选择,整数类型 > 字符串类型 > ENUM和SET类型(一般避免)

后续持续完善...

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

推荐阅读更多精彩内容