1.[强制] 表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是unsigned tinyint(1表示是,0表示否)。
说明: 任何字段如果为非负数,必须是unsigned。
正例: 表达逻辑删除的字段名is_deleted,1表示删除,0表示未删除。
老四附言:
为什么强制要求数据类型是unsigned的呢?我们来简单来浅析一下。关于mysql中的unsigned,拿tinyint来说,我们知道如果unsigned之后它的取值范围就变成了0~255,默认的signed是-128~127,所以当我们明确要使用非负数的时候,其实从空间上来讲我们多了一倍的使用空间。再从性能方面上来说,如果我们查询500以下的数据,那么定义了unsigned的字段性能会更好,因为MySQL会将范围定义到0~500,反而,signed会从-2147483648(-2^31)~500。所以综合以上,设置unsigned在提高特定需求的空间使用率以及性能提升方面有优势的,所以请尽量这样设计你的数据表。
还有就是注意在映射Entity中POJO的属性不要用is打头,避免在使用RPC(远程服务调用)的时候遇到各种意外的情况,在pojo与mapper之间做属性和数据库字段的映射,这也是孤尽等一众大佬程序员总结过来的经验。
2.[强制] 表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
说明:MySQL在Windows下不区分大小写,但在Linux下默认是区分大小写。因此,数据库名、表名、字段名,都不允许出现任何大写字母,避免节外生枝。
正例: aliyun_admin,rdc_config,level3_name
反例: AliyunAdmin,rdcConfig,level_3_name
老四附言:
谈到预发布,老四就觉得苦不堪言,因为公司较小,技术管理不太完善,没有宇发布流程,遇到重大版本上线几乎每次都是深夜,砥砺前行吧。关于这条规约,记住你养成使用小写的习惯就好了,千万不要受Navicat这种工具的影响。
3.[强制] 表名不使用复数名词。
说明: 表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于DO(Domain Object,领域对象)类名也是单数形式,符合表达习惯。
老四解析:不说了,经常犯这种错误,骨子里是每次都能深刻的意识到的,但是每次因为不敢乱动数据库就不了了之了。
4.[强制] 禁用保留字,如desc、range、match、delayed等,请参考MySQL官方保留字。
老四附言:
其实MySQL官方是支持关键字作为字段名来使用的,但是针对保留关键字是必须要加引用()。但是如规约所述,保留字和关键字都尽量不要使用,别用就对了。
MySQL8.0官方保留字如下(给予官方说法: 在某些情况下,您可能会升级到更高版本,因此最好查看未来的保留字。您可以在涵盖更高版本MySQL的手册中找到这些内容。列表中的大多数保留字都被标准SQL禁止作为列名或表名(例如 GROUP
)。有一些是保留的,因为MySQL需要它们并使用yacc分析器):
MySQL 8.0删除了关键字和保留字,以下列表显示了与MySQL5.7相比,在MySQL 8.0中删除的关键字和保留字。
- ANALYSE
- DES_KEY_FILE
- PARSE_GCOL_EXPR
- REDOFILE
- SQL_CACHE
至于保留字实在太多,太占篇幅,考虑到MySQL的官网还没有被墙,所以放出两个链接供您自己查阅参考。
5.[强制] 主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。
说明: pk_即primary key;uk_即unique key;idx_即index的简称。
老四附言:
我还能说点啥?
6.[强制] 小数类型为decimal,禁止使用float和double。
说明: float和double在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过decimal的范围,建议将数据拆成整数和小数分开存储。
老四附言:
float和double这种问题其实在Java中也存在,在Java中我们都用BigDecimal。相反,如果不是真的合适,尤其像互联网的项目,要求的都比较精确,所以尽量避免使用浮点数给自己找麻烦。
简单谈一下Java中关于浮点数的误差以及BigDecimal的使用注意事项。
首先我们大致了解一下浮点数的构成。浮点数N由尾数M、基数R(一般为2)以及阶码E(整数)组成N=M*R^E的形式,尾数决定了精度,E决定了浮点数的范围。所以很多时候这个公式决定了浮点数误差的存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package com.glorze.interview.one; /** * 测试浮点数误差 * @ClassName Test * @author: glorze.com * @since: 2018年5月20日 下午1:26:52 */ public class Test { public static void main(String[] args) { double glorze = 0d; Integer num = 50; for(int i = 0; i < num; i++) { glorze += 0.1; } System.out.println("result: " + glorze); System.out.println("我们期待输出29,而结果却是: " + (int)(29.0 * 0.01 * 100)); } } |
所以在对计算精确度有高要求的业务场景中,不能使用浮点数,而要使用BigDecimal进行精确计算。他是Java中标准的类库,支持任意精度的小数。关于基本用法,可能不需要我告诉你,说几点注意事项:
尽量使用字符串String类型进行函数的构造。因为比较准确,你可以自行比较一下new BigDecimal(0.333)和new BigDecimal(“0.333”)的输出结果就很明了了。
除法操作的时候要设置保留的小数位数。万一碰到无限循环会抛异常。
用BigDecimal的compareTo()方法进行数字的比较而不要使用equals()方法。你使用compareTo()方法去比较1和1.000是返回true的,但是equals就不行了。
7.[强制] 如果存储的字符串长度几乎相等,使用char定长字符串类型。
老四附言:
其实我更建议还是使用varchar类型,因为毕竟varchar类型的特点是你用了多少就占用多少,而char是你定义了多少就占用多少,我们其实也很少碰到字段统一存储的那种现象(排除状态那种字段),仁者见仁智者见智吧。
8.[强制] varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
老四附言:
没毛病
9.[强制] 表必备三字段:id,gmt_create,gmt_modified。
说明: 其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。gmt_create,gmt_modified的类型均为datetime类型,前者现在时表示主动创建,后者过去分词表示被动更新。
老四附言:
id字段无需多说,当然如果你设置id为varchar累心需要自己生成字符串。至于gmt_create,gmt_modified这样的设计作用是什么呢?当记录修改时,gmt_modified表示最近修改时间,如果记录没有修改,两个字段的值一样。作用就是可以统计每天对这张表做了多少次的DML(Data Manipulation Language,数据操纵语言)。
10.[推荐] 表的命名最好是加上”业务名称_表的作用”。
正例: alipay_task/force_project/trade_config
老四附言:
一般这样做你会很容易记住表名,知道他是用来干嘛的,不要xjb起名,时间长了,select的时候都不知道表名叫什么。
11.[推荐] 库名与应用名称尽量一致。
老四附言:
具体情况具体分析,如果你多个项目的那种维护,按照项目名称来作为数据库的名字会很清晰明了,如果你就这一个库,最好还是复杂一些,无关一些,这样更安全一些。
12.[推荐] 如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
老四附言:
无论是建表,新增字段,修改字段等都要使用comment标注注释,这是对别人的一种方便,对项目的一种负责。
13.[推荐] 字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:
- 不是频繁修改的字段。
- 不是varchar超长字段,更不能是text字段。
正例: 商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存储类目名称,避免关联查询。
老四附言:
没啥可说的,但我强迫症,这句话必须得有。
14.[推荐] 单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。
说明: 如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
关于分库分表,老四知道的国内比较有名的可能就是Mycat了,他是基于阿里开源的Cobar而研发,老四刚刚北漂的时候公司就用这个东西,虽然用着不错,但是也遇到了很多坑,在使用某一项技术或者产品的时候多读多看吧!
15.[参考] 设置合适的字符存储长度,不但可以节约数据库表空间和索引存储,更重要的是能够提升检索速度。
正例: 见下表,其中无符号值可以避免误存负数,且扩大了表示范围。
对象 | 年龄区间 | 类型 | 字节 | 表示范围 |
人 | 150 岁之内 | unsigned tinyint | 1 | 无符号值: 0到255 |
龟 | 数百岁 | unsigned smallint | 2 | 无符号值: 0到65535 |
恐龙化石 | 数千万年 | unsigned int | 4 | 无符号值: 0到约42.9亿 |
太阳 | 约50亿年 | unsigned bigint | 8 | 无符号值: 0到约10的19 次方 |
老四附言:
请参考第一条附言。
更博不易,如果觉得文章对你有帮助并且有能力的老铁烦请赞助盒烟钱,点我去赞助。抱拳。