阿里巴巴 JAVA 开发手册--总结

(一) 命名规约
1、所有编程相关命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。

2、所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。 说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式 也要避免采用。

抽象类:以Abstract或者Base开头;
异常类:使用 Exception 结尾;
测试类:以它要测试的类的名称开始,以 Test 结尾。
POJO 类中的任何布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。
             如果使用到了设计模式,建议在类名中体现出具体模式。 
枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。

说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。
正例:枚举名字:DealStatusEnum;成员名称:SUCCESS / UNKOWN_REASON。 

3、类名使用 UpperCamelCase 风格;

方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格。
常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用 复数形式。

4、接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁性,并加上有效的 javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。

对于 Service 和 DAO 类,基于 SOA (面向服务架构)的理念,暴露出来的服务一定是接口,内部 的实现类用 Impl 的后缀与接口区别。

(二) 常量定义
1、不允许出现任何魔法值(即未经定义的常量)直接出现在代码中。

2、long 或者 Long 初始赋值时,必须使用大写的 L,不能是小写的 l,小写容易跟数字 1 混淆,造成误解。
说明:Long a = 2l; 写的是数字的 21,还是 Long 型的 2?

(三) OOP
1、避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成 本,直接用类名来访问即可。

2、所有的覆写方法,必须加@Override 注解。

3、所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。

(四) Mysql
1、表名不使用复数名词。

2、小数类型为 decimal,禁止使用 float 和 double。

说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

对于精度比较高的东西,比如money,我会用decimal类型,不会考虑float,double,因为他们容易产生误差,numeric和decimal同义,numeric将自动转成decimal。

DECIMAL从MySQL 5.1引入,列的声明语法是DECIMAL(M,D)。在MySQL 5.1中,参量的取值范围如下:

·M是数字的最大数(精度)。其范围为1~65(在较旧的MySQL版本中,允许的范围是1~254),M 的默认值是10。

·D是小数点右侧数字的数目(标度)。其范围是0~30,但不得超过M。

说明:float占4个字节,double占8个字节,decimail(M,D)占M+2个字节。

例如:decimal(5, 1)  范围为-9999.9 到 99999.9

3、表必备三字段:id, gmt_create, gmt_modified。

说明:其中 id 必为主键,类型为 unsigned bigint、单表时自增、步长为 1;分表时改为从 TDDL Sequence 取值,确保分表之间的全局唯一。
主键是自增长的类型,因为一般来说,用户都希望主键是非负数。然而在实际使用中,UNSIGNED可能会带来一些负面的影响。

java中没有无符号类型,而解决办法就是选择比无符号更大的数据类型。

#include
    int main(){
        unsigned int a;
        unsigned int b;
        a = 1;
        b = 2;
        printf(a - b: %d\n,a-b);
        printf(a - b: %u\n,a-b);
        return 1;
}

//上述代码的运行结果是:
a - b: -1
a - b: 4294967295

gmt_create, gmt_modified 的类型均为 date_time 类型。
gmt_create表示记录创建时间,gmt_modified表示最近修改时间;
如果记录没有修改,gmt_create和gmt_modified一致。

GMT(格林尼治标准时间)一般指世界时

mysql中存储时间,我们可以用datetime 格式,timestamp格式,也可以用int格式。

DATETIME格式,默认是"YYYY-MM-DD HH:MM:SS",这19个字符表示的,从1000-01-01 00:00:00-9999-12-31 23:59:59 。

TIMESTAMP格式也是'YYYY-MM-DD HH:MM:SS'这样的,与DATETIME不同的地方是,它的年份取值范围是1970-2037。

INT 的格式就是整数的形式,它可以控制位数,一般我们设置成10位就可以了。(php内置函数date()可以转换int类型的时间)

创建时的时间:

create_time timestamp not null default now();

设置为更新的时候,自动修改值,也就是说当我们修改数据库,比如插入或者更新的时候,这个字段当我们设置成

CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,时,它就会自动填入当前的时间。
create table demotime(
    id int primary key auto_increment,
    gtm_create datetime default null,
    gtm_modified timestamp not null default current_timestamp on update current_timestamp
);

-- 添加数据时用 current_timestamp插入创建时间
insert into demotime(gtm_create) values(current_timestamp);

-- on update current_timestamp 由这句话,可以在更新数据时同时更新时间
update demotime set id=100 where id=1;

4、单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。

5、合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索 速度。 正例:人的年龄用 unsigned tinyint(表示范围 0-255,人的寿命不会超过 255 岁);海龟就 必须是 smallint,但如果是太阳的年龄,就必须是 int;如果是所有恒星的年龄都加起来,那 么就必须使用 bigint。

类型大小范围(有符号)范围(无符号)用途
tinyint1 字节(-128,127)(0,255)小整数值
smallint2 字节(-32 768,32 767)(0,65 535)大整数值
mediumint3 字节(-8 388 608,8 388 607)(0,16 777 215)大整数值
INT或INTEGER4 字节(-2 147 483 648,2 147 483 647)(0,4 294 967 295)大整数值

6、在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据
实际文本区分度决定索引长度。
说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来
确定。

6、超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引。
说明:即使双表 join 也要注意表索引、SQL 性能

7、页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索
引。

8、如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索
引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。
正例:where a=? and b=? order by c; 索引:a_b_c
反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引 a_b
无法排序。

9、利用覆盖索引来进行查询操作,来避免回表操作。
说明:如果一本书需要知道第 11 章是什么标题,会翻开第 11 章对应的那一页吗?目录浏览一
下就好,这个目录就是起到覆盖索引的作用。

正例:IDB 能够建立索引的种类:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的
一种效果,用 explain 的结果,extra 列会出现:using index.

10、利用延迟关联或者子查询优化超多分页场景。

说明: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

11、SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts最好。
说明:
1)consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
2)ref 指的是使用普通的索引。(normal index)
3)range 对索引进范围检索。

反例:explain 表的结果,type=index,索引物理文件全扫描,速度非常慢,这个 index 级别比较 range 还低,与全表扫描是小巫见大巫。

12、建组合索引的时候,区分度最高的在最左边。

正例:如果 where a=? and b=? ,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可。

说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>?
and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列。

13、创建索引时避免有如下极端误解:
1)误认为一个查询就需要建一个索引。
2)误认为索引会消耗空间、严重拖慢更新和新增速度。
3)误认为唯一索引一律需要在应用层通过“先查后插”方式解决。

(五) SQL

1、不要使用 count(列名)或 count(常量)来替代 count(),count()就是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。

说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。

2、count(distinct col) 计算该列除 NULL 之外的不重复数量。注意 count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。

3、当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为NULL,因此使用 sum()时需注意 NPE 问题。

正例:可以使用如下方式来避免 sum 的 NPE 问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM
table;

4、使用 ISNULL()来判断是否为 NULL 值。注意:NULL 与任何值的直接比较都为 NULL。
说明:
1) NULL<>NULL 的返回结果是 NULL,不是 false。
2) NULL=NULL 的返回结果是 NULL,不是 true。
3) NULL<>1 的返回结果是 NULL,而不是 true。

5、在代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执行后面的分页语句。

6、禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

7、不得使用外键与级联,一切外键概念必须在应用层解决。
说明:(概念解释)学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。
如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,则为级联更新。外
键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据
库更新风暴的风险;外键影响数据库的插入速度。

8、TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE 无事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使用此语句。

说明:TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同。

(六) ORM

1、在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
说明:1)增加查询分析器解析成本。2)增减字段容易与 resultMap 配置不一致。

2、不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要
定义;反过来,每一个表也必然有一个与之对应。
说明:配置映射关系,使字段与 DO 类解耦,方便维护。

3、xml 配置中参数注意使用:#{},#param# 不要使用${} 此种方式容易出现 SQL 注入。

4、iBATIS 自带的 queryForList(String statementName,int start,int size)不推荐使
用。

说明:其实现方式是在数据库取到 statementName 对应的 SQL 语句的所有记录,再通过 subList
取 start,size 的子集合,线上因为这个原因曾经出现过 OOM。

正例:在 sqlmap.xml 中引入 #start#, #size#

Map<String, Object> map = new HashMap<String, Object>();
map.put("start", start);
map.put("size", size); 

5、不允许直接拿 HashMap 与 HashTable 作为查询结果集的输出。
反例:某同学为避免写一个<resultMap>,直接使用 HashTable 来接收数据库返回结果,结果
出现日常是把 bigint 转成 Long 值,而线上由于数据库版本不一样,解析成 BigInteger,导
致线上问题。

6、更新数据表记录时,必须同时更新记录对应的 gmt_modified 字段值为当前时间。

7、不要写一个大而全的数据更新接口,传入为 POJO 类,不管是不是自己的目标更新字
段,都进行 update table set c1=value1,c2=value2,c3=value3; 这是不对的。执行 SQL 时,
尽量不要更新无改动的字段,一是易出错;二是效率低;三是 binlog 增加存储。

8、@Transactional 事务不要滥用。事务会影响数据库的 QPS,另外使用事务的地方需要
考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。

9、<isEqual>中的 compareValue 是与属性值对比的常量,一般是数字,表示相等时带上
此条件;<isNotEmpty>表示不为空且不为 null 时执行;<isNotNull>表示不为 null 值时执行。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值