带你读《2022技术人的百宝黑皮书》——开发规约的意义与细则(4)https://developer.aliyun.com/article/1339986?groupCode=taobaotech
SQL规约
- 不要使用count(列名)或count(常量)来替代count(*),count(*)就是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。说明:count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的行。
- count(distinct col) 计算该列除NULL之外的不重复数量。注意 count(distinct col1, col2) 如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0。
- 当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为NULL,因此使用sum()时 需注意NPE问题。正例:可以使用如下方式来避免sum的NPE问题:SELECT IFNULL(SUM(column), 0) FROM table;
- 对于数据库中表记录的查询和变更,只要涉及多个表,都需要在列名前加表的别名(或表名)进行限定。说 明:对多表进行查询记录、更新记录、删除记录时,如果对操作列没有限定表的别名(或表名),并且操作列 在多个表中存在时,就会抛异常。正例:select t1.name from table_first as t1 , table_second as t2 where t1.id=t2.id;反例:在飞猪某业务中,由于多表关联查询语句没有加表的别名(或表名)的限制,正常运行两年 后,最近在某个表中增加一个同名字段,在预发布环境做数据库变更后,线上查询语句出现出1052异常: Column 'name' in field list is ambiguous,导致票务交易下跌。
- 在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。
- 不得使用外键与级联,一切外键概念必须在应用层解决。说明:(概念解释)学生表中的student_id是主键,那么成绩表中的student_id则为外键。如果更新学生表中的student_id,同时触发成绩表中的student_id更新,则为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
- 禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
- IDB数据订正(特别是删除或修改记录操作)时,要先select,避免出现误删除,确认无误才能提交执行。
- SQL语句中表的别名前加as,并且以t1、t2、t3、...的顺序依次命名。说明:1)别名可以是表的简称,或者依 据表在SQL语句中出现的顺序,以t1、t2、t3的方式命名。2)别名前加as使别名更容易识别。正例:select t1.name from table_first as t1, table_second as t2 where t1.id=t2.id;
- in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控制在1000个之内。
- 因国际化需要,所有的字符存储与表示,均采用utf8字符集,那么字符计数方法注意:说明:SELECT LENGTH("阿里巴巴");返回为12SELECT CHARACTER_LENGTH("阿里巴巴");返回为4如果需要存储表 情,那么选择utf8mb4来进行存储,注意它与utf8编码的区别。
ORM规约
- 在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。说明:1)增加查询分析器解析成本。2)增减字段容易与resultMap配置不一致。3)多余字段增加网络消耗,尤其是 text 类型的字段。
- POJO类的布尔属性不能加is,而数据库字段必须加is_,要求在resultMap中进行字段与属性之间的映射。说明:参见定义POJO类以及数据库字段定义规定,在sql.xml增加映射,是必须的。
- 不要用resultClass当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义;反过来,每一个表也 必然有一个与之对应。说明:配置映射关系,使字段与DO类解耦,方便维护。
- sql.xml配置中参数注意:#{},#param# 不要使用${} 此种方式容易出现SQL注入。
- iBATIS自带的queryForList(String statementName,int start,int size)不推荐使用。说明:其实现方式是在数据库取到statementName对应的SQL语句的所有记录,再通过subList取start,size的子集合,线上因为这个原 因曾经出现过OOM。正例:在sqlmap.xml中引入 #start#, #size#
Map<String, Object> map = new HashMap<>(16); map.put("start", start); map.put("size", size);
- 不允许直接拿HashMap与HashTable作为查询结果集的输出。反例:某同学为避免写一个xxx,直接使用HashTable来接收数据库返回结果,结果出现日常是把bigint转成Long值,而线上由于数据库版本不一样,解析成BigInteger,导致线上问题。
- 更新数据表记录时,必须同时更新记录对应的gmt_modified字段值为当前时间。
带你读《2022技术人的百宝黑皮书》——开发规约的意义与细则(6)https://developer.aliyun.com/article/1339984?groupCode=taobaotech