1. 命名规约
- 抽象类命名使用Abstract或Base开头
- 异常类命名使用Exception结尾
- 测试类命名以它要测试的类的名称开始,以Test结尾
- 中括号是数组类型的一部分,数组定义如下:
string[] args;
- POJO类中,布尔类型的变量都不要加
is
,否则部分框架解析会引起序列化错误 - 接口类中的方法和属性不要加任何修饰符号(
public
也不要加),保持代码的简洁性,并加上有效的Javadoc注释 - 对于Service和DAO层,基于SOA的理念,暴露出来的服务一定是接口,内部的实现类用Impl的后缀与接口区别
- Service/DAO层命名规约
- 获取单个对象的方法用
get
做前缀 - 获取多个对象的方法用
list
做前缀 - 获取统计值的方法用
count
做前缀 - 插入方法用
save
(推荐)或insert做前缀 - 删除方法用
remove
(推荐)或delete做前缀 - 修改的方法用
update
做前缀
- 获取单个对象的方法用
- 领域模型命名规范
- 数据模型:xxxDO,xxx表示数据表名
- 数据传输对象:xxxDTO,xxx为业务领域相关的名称
- 展示对象:xxxVO,xxx一般为网页名称
- POJO是DO/DTO/BO/VO的统称,禁止命名为xxxPOJO
用户发出请求(可能是填写表单),表单的数据在展示层被匹配为VO。
展示层把VO转换为服务层对应方法所要求的DTO,传送给服务层。
服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。
服务层把DO转换为持久层对应的PO(可以使用ORM工具,也可以不用),调用持久层的持久化方法,把PO传递给它,完成持久化操作。
对于一个逆向操作,如读取数据,也是用类似的方式转换和传递,略。
2.OOP规约
- 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名访问即可
- 所有的覆写方法,必须加
@Override
注解 - 尽量不用可变参数编程。如果使用,相同参数类型,相同业务含义,才可以使用可变参数,避免使用Object
- 不能使用过时的类或方法
- 所有相同类型的包装类对象之间值比较,全部使用
equals
方法比较。对于-128~127
之间的Integer值,可以使用==
进行值比较(这个区间Integer对象是在IntegerCache.cache产生,会复用已有对象。但是这个区间外的所有数据都会在堆上产生,并不会复用已有对象) - 定义DO/DTO/VO等POJO类时,不要设定任何属性默认值
- 序列化类新增属性时,请不要修改
serialVersionUID
字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改seriaVersionUID
值 - 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在
init
方法中 - POJO类必须写
toString
方法 - 类成员与方法访问控制从严
- 如果不允许外部直接通过
new
来创建对象,那么构造方法必须是private
- 工具类不允许有
public
或default
构造方法 - 类非
static
成员变量并且与子类共享,必须是protected
- 类非
static
成员变量并且仅在本类使用,必须是private
- 类
static
成员变量如果仅在本类使用,必须是private
- 若是
static
成员变量,必须考虑是否为final
- 类成员方法只供类内部调用,必须是
private
- 类成员方法只对继承公开,那么限制为
protected
- 如果不允许外部直接通过
3.集合处理
- 关于
hashCode
和equals
- 只要重写
equals
,就必须重写hashCode
- 因为Set存储的是不重复的对象,依据
hashCode
和equals
判断,所以Set存储的对象必须重写这两个方法 - 如果自定义对象作为Map键,那么必须重写
hashCode
和equals
- String重写了
hashCode
和equals
方法,所以我们可以愉快地使用String对象作为key来使用
- 只要重写
- 不要在foreach循环里进行元素的remove/add操作。remove元素请使用
Iterator
方式,如果并发操作,需要对Iterator
对象加锁 - 使用
entrySet
遍历Map集合KV,而不是keySet
方式进行遍历
4.注释规约
- 类、类属性、类方法的注释必须使用Javadoc规范,不得使用
//XXXX
方式 - 所有的抽象方法(包括接口中的方法)必须要用Javadoc注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能
- 所有的类必须添加创建者信息
- 所有的枚举类型字段必须要有注释,说明每个数据项的用途
5.异常处理
- 不要捕获Java类库中定义的继承自
RuntimeException
的运行时异常类,如:IndexOutOfBoundsException
/NullPointerException
,这类异常由程序员预检查来规避,保证程序健壮性 - 异常不要用来做流程控制、条件控制,因为异常的处理效率比条件分支低
- 对大段代码进行try-catch,这是不负责任的表现,对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理
finally
块必须对资源对象、流对象进行关闭,有异常也要做try-catch- 不能在
finally
块中使用return
。finally块中的return返回后方法结束执行,不会再执行try块中的return语句 - 防止NPE
- 返回类型为包装数据类型,有可能是
nul
l - 数据库的查询结果有可能为
null
- 集合里的元素即使
isNotEmpty
,取出的数据元素也可能为null
- 远程调用返回对象,一律要求进行NPE判断
- 对于Session中获取的数据,建议NPE检查,避免空指针
- 级联调用容易产生NPE。如
obj.getA().getB().getC()
- 返回类型为包装数据类型,有可能是
6.MySQL规约
6.1 建表规约
- 表达是与否概念的字段,必须使用
is_xxx
的方式命名,数据类型是unsigned tinyint
(1表示是,0表示否) - 表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只出现数字。
- 表名不使用复数名词
- 唯一索引为
uk_字段名
;普通索引则为inx_字段名
- 小数类型为
decimal
,禁止使用double
和float
- 表必备三字段:id、create_at、update_at
- 表的命名最好是加上
业务名称_表的作用
- 库名与应用名称尽量一致
- 字段允许适当冗余,以提高性能,但是必须考虑数据同步的情况。同时冗余字段应
- 不是频繁修改的字段
- 不是
varchar
超长字段,更不能是text
字段
6.2 索引规约
- 业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引
- 超过三个表禁止join。需要join的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引
- 在
varchar
字段上建立索引时,必须制定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度 - 页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决
- 如果有
order by
的场景,请注意利用索引的有序性。order by
最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file _ sort
的情况,影响查询性能 - 利用覆盖索引来进行查询操作,来避免回表操作
- 利用延迟关联或者子查询优化超多分页场景
- 建组合索引的时候,区分度最高的在最左边
- 创建索引时避免有如下极端误解
- 误认为一个查询就需要建一个索引
- 误认为索引会消耗空间、严重拖慢更新和新增速度
- 误认为唯一索引一律需要在应用层通过“先查后插”方式解决
6.3 SQL
- 不要使用
count(列名)
或count(常量)
来替代count(*)
,count(*)
就是 SQL 92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关count(*)
会统计值为 NULL 的行,而count(列名)
不会统计此列为 NULL 值的行
count(distinct col)
计算该列除 NULL 之外的不重复数量。注意count(distinctcol 1, col 2)
如果其中一列全为 NULL ,那么即使另一列有不同的值,也返回为 0- 不得使用外键与级联,一切外键概念必须在应用层解决
- 禁止使用存储过程,存储过程难以调试和扩展,更没有移植性
- 数据订正时,删除和修改记录时,要先
select
,避免出现误删除,确认无误才能执行更新语句 in
操作能避免则避免,若实在避免不了,需要仔细评估in
后边的集合元素数量,控制在1000个之内- TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE无事务且不触发 trigger ,有可能造成事故,故不建议在开发代码中使用此语句
6.4 ORM规约
- 在表查询中,一律不要使用
*
作为查询的字段列表,需要哪些字段必须明确写明 - POJO 类的
boolean
属性不能加is
,而数据库字段必须加is _
,要求在resultMap
中进行字段与属性之间的映射 - 不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义 ; 反过来,每一个表也必然有一个与之对应
- xml 配置中参数注意使用:#{},# param # 不要使用${} 此种方式容易出现 SQL 注入
- 不允许直接拿
HashMap
与Hashtable
作为查询结果集的输出 - 更新数据表记录时,必须同时更新记录对应的
gmt _ modified(update_at)
字段值为当前时间 - 不要写一个大而全的数据更新接口,传入为 POJO 类,不管是不是自己的目标更新字段,都进行 update table set c1=value1,c2=value2,c3=value3; 这是不对的。执行 SQL时,尽量不要更新无改动的字段,一是易出错 ; 二是效率低 ; 三是 binlog 增加存储
- @ Transactional 事务不要滥用。事务会影响数据库的 QPS ,另外使用事务的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等