## java开发规范
>在我们的日常开发过程中好的代码开发规范是必不可少的,下面我们来注意一下具体要注意哪些。
### **1.类名使用** `UpperCamelCase` **风格**
>例如:`ForceCode` `UserDO` `HtmlDTO` `XmlService` `TcpUdpDeal` `TaPromotion`
### **2.方法名、参数名、成员变量、局部变量都统一使用** `lowerCamelCase` **风格。**
>例如:`localValue` `getHttpMessage()` `inputUserId`
### **3.常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。**
>例如:`MAX_STOCK_COUNT` `CACHE_EXPIRED_TIME`
### **4.抽象类命名使用** `Abstract` **或** `Base` **开头;异常类命名使用** `Exception` **结尾;测试类命名以它要测试的类的名称开始,以** `Test` **结尾。**
### **5.类型与中括号紧挨相连来表示数组。**
>定义整形数组 `int[]` `arrayDemo`
### **6.**`POJO` **类中的任何布尔类型的变量,都不要加** `is` **前缀,否则部分框架解析会引起序列化错误。**
>例如:在本文 MySQL 规约中的建表约定第一条,表达是与否的值采用 is_xxx 的命名方式,所以,需要在设置从 is_xxx 到 xxx 的映射关系。
### **7.包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。**
>例如:应用工具类包名为 `com.alibaba.ei.kunlun.aap.util`类名为 `MessageUtils`(此规则参考 `spring` 的框架结构)
### **8.在** `long` **或者** `Long` **赋值时,数值后使用大写的 L,不能是小写的 l,小写容易跟数字混淆,造成误解。**
>例如:Long a = 2l; 写的是数字的 21,还是 Long 型的 2。
### **9.不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。**
>例如:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解,也不利于维护。
### **10.如果变量值仅在一个固定范围内变化用** `enum` **类型来定义。**
>说明:如果存在名称之外的延伸属性应使用 `enum` 类型,下面正例中的数字就是延伸信息,表示一年中的第几个季节。
```
public enum SeasonEnum {
SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
private int seq;
SeasonEnum(int seq) {
this.seq = seq;
}
public int getSeq() {
return seq;
}
}
```
### **11.** `IDE` **的** `text file encoding` **设置为** `UTF-8`; `IDE` **中文件的换行符使用** `Unix` **格式,不要使用** `Windows` **格式。**
### **12.任何货币金额,均以最小货币单位且整型类型来进行存储。**
### **13.浮点数之间的等值判断,基本数据类型不能用** `==` **来比较,包装数据类型不能用** `equals` **来判断。**
>说明:浮点数采用“尾数+阶码”的编码方式,类似于科学计数法的“有效数字+指数”的表示方式。二进制无法精确表示大部分的十进制小数。
```
float a = 1.0f - 0.9f;
float b = 0.9f - 0.8f;
float diff = 1e-6f;
if (Math.abs(a - b) < diff) {
System.out.println("true");
}
```
### **14.类成员与方法访问控制从严。**
>1) 如果不允许外部直接通过 `new` 来创建对象,那么构造方法必须是 `private`。
>2) 工具类不允许有 `public` 或 `default` 构造方法。
>3) 类非 `static` 成员变量并且与子类共享,必须是 `protected`。
>4) 类非 `static` 成员变量并且仅在本类使用,必须是 `private`。
>5) 类 `static` 成员变量如果仅在本类使用,必须是 `private`。
>6) 若是 `static` 成员变量,考虑是否为 `final`。
>7) 类成员方法只供类内部调用,必须是 `private`。
>8) 类成员方法只对继承类公开,那么限制为 `protected`。
### **说明:**
任何类、方法、参数、变量,严控访问范围。过于宽泛的访问范围,不利于模块解耦。思考:如果是一个 `private` 的方法,想删除就删除,可是一个 `public` 的 `service` 成员方法或成员变量,删除一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视线内,变量作用域太大,无限制的到处跑,那么你会担心的。
### **15.用户敏感数据禁止直接展示,必须对展示数据进行脱敏。**
>说明:中国大陆个人手机号码显示为:137****0969,隐藏中间 4 位,防止隐私泄露。
### **16.用户输入的** `SQL` **参数严格使用参数绑定或者** `METADATA` **字段值限定,防止** `SQL` **注入,禁止字符串拼接** `SQL` **访问数据库。**
### **17.用户请求传入的任何参数必须做有效性验证。**
>说明:忽略参数校验可能导致:
>1.`page size` 过大导致内存溢出
>2.恶意 `order by` 导致数据库慢查询
>3.缓存击穿
>4.`SSRF`
>5.任意重定向
>6.`SQL` 注入,`Shell` 注入,反序列化注入
>7.正则输入源串拒绝服务 `ReDoS`
**Java 代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没有问题,但是如果攻击人员使用
的是特殊构造的字符串来验证,有可能导致死循环的结果。**
### **18.禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据。**
### **19.表单、AJAX 提交必须执行 CSRF 安全验证。**
>说明:CSRF(Cross-site request forgery)跨站请求伪造是一类常见编程漏洞。对于存在 CSRF 漏洞的应用/网站,攻击者可以事先构造好 URL,只要受害者用户一访问,后台便在用户不知情的情况下对数据库中用户参数进行相应修改。
### **20.URL 外部重定向传入的目标地址必须执行白名单过滤。**
### **21.在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放的机制,如数量限制、疲劳度控制、验证码校验,避免被滥刷而导致资损。**
>说明:如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其它用户,并造成短信平台资源浪费。
### **22.发贴、评论、发送即时消息等用户生成内容的场景必须实现防刷、文本内容违禁词过滤等风控策略。**
### **23.数据库表约定。**
1).表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
>说明:`MySQL` 在 `Windows` 下不区分大小写,但在 `Linux` 下默认是区分大小写。因此,数据库名、表名、字段名,都不允许出现任何大写字母,避免节外生枝。
例如:`aliyun_admin` `rdc_config` `level3_name`
2).表达 `是与否` 概念的字段,必须使用 `is_xxx` 的方式命名,数据类型是 `unsigned tinyint`(1 表示是,0 表示否)。
>说明:任何字段如果为非负数,必须是 `unsigned`。
>注意:POJO 类中的任何布尔类型的变量,都不要加 `is` 前缀,所以,需要在设置从 `is_xxx` 到 `Xxx` 的映射关系。数据库表示是与否的值,使用 `tinyint` 类型,坚持 `is_xxx` 的命名方式是为了明确其取值含义与取值范围。
>例如:表达逻辑删除的字段名 `is_deleted`,1 表示删除,0 表示未删除。
3).主键索引名为 `pk_`字段名;唯一索引名为 `uk_`字段名;普通索引名则为 `idx_`字段名。
>说明:`pk_` 即 `primary key`;`uk_` 即 `unique key`;`idx_` 即 `index` 的简称。
4).小数类型为 `decimal`,禁止使用 `float` 和 `double`。
>说明:在存储的时候,`float` 和 `double` 都存在精度损失的问题,很可能在比较值的时候,得到不正确的结果。如果存储的数据范围超过 `decimal` 的范围,建议将数据拆成整数和小数并分开存储。
5).如果存储的字符串长度几乎相等,使用 `char` 定长字符串类型。
6).`varchar` 是可变长字符串,不预先分配存储空间,长度不要超过 `5000`,如果存储长度大于此值,定义字段类型为 `text`,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
7).表必备三字段:`id` `gmt_create` `gmt_modified`。
说明:其中 `id` 必为主键,类型为 `bigint unsigned` 单表时自增、步长为 `1`。`gmt_create` `gmt_modified`的类型均为 `datetime` 类型,前者现在时表示主动式创建,后者过去分词表示被动式更新。
8).表的命名最好是遵循 `业务名称_表的作用`。
>例如:`alipay_task` `force_project` `trade_config`
9).库名与应用名称尽量一致。
10).如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
11).字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:
>1) 不是频繁修改的字段。
>2) 不是唯一索引的字段。
>3) 不是 `varchar` 超长字段,更不能是 `text` 字段。
>说明:各业务线经常冗余存储商品名称,避免查询时需要调用 `IC` 服务获取。
10).单表行数超过 `500` 万行或者单表容量超过 `2GB`,才推荐进行分库分表。
>说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
11).合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。
>说明:无符号值可以避免误存负数,且扩大了表示范围。
### **24.索引规约**
1).业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。
>说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。
2).超过三个表禁止 `join`。需要 `join` 的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引。
>说明:即使双表 `join` 也要注意表索引、`SQL 性能`。
3).在 `varchar` 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。
>说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))count(*)的区分度来确定。
4).如果有 `order by` 的场景,请注意利用索引的有序性。`order by` 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 `file_sort` 的情况,影响查询性能。
>说明:where a=? and b=? order by c; 索引:a_b_c
5).利用覆盖索引来进行查询操作,避免回表。
>说明:如果一本书需要知道第 11 章是什么标题,会翻开第 11 章对应的那一页吗?目录浏览一下就好,这个目录就是起到覆盖索引的作用。
>例如:能够建立索引的种类分为主键索引、唯一索引、普通索引三种,而覆盖索引只是一种查询的一种效果,用 `explain` 的结果,`extra` 列会出现:`using index`。
7).利用延迟关联或者子查询优化超多分页场景。
>说明:`MySQL` 并不是跳过 `offset` 行,而是取 `offset+N` 行,然后返回放弃前 `offset` 行,返回 `N` 行,那当 `offset` 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL改写。
>正例:先快速定位需要获取的 id 段,然后再关联:
```
SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
```
8).`SQL` 性能优化的目标:至少要达到 `range` 级别,要求是 `ref` 级别,如果可以是 `consts` 最好。
>1) `consts` 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
>2) `ref` 指的是使用普通的索引`(normal index)`。
>3) `range` 对索引进行范围检索。
9).建组合索引的时候,区分度最高的在最左边。
>例如:如果 where a=? and b=?,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可。
### **25.不得使用外键与级联,一切外键概念必须在应用层解决。**
>说明:(概念解释)学生表中的 `student_id` 是主键,那么成绩表中的 `student_id` 则为外键。如果更新学生表中的 `student_id`,同时触发成绩表中的 `student_id` 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
### **26.禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。**
### **27.数据订正(特别是删除或修改记录操作)时,要先 select,避免出现误删除,确认无误才能执行更新语句。**
### **28.在表查询中,一律不要使用** `*` **作为查询的字段列表,需要哪些字段必须明确写明。**
>1)增加查询分析器解析成本。
>2)增减字段容易与 `resultMap` 配置不一致。
>3)无用字段增加网络消耗,尤其是 `text` 类型的字段。