“一个优秀的工程师和一个普通工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。”——毕玄

 编程规约[写完]

(一)命名风格[写完]

1.命名不能以下划线或美元符号开始和结束

反例:
name /__name /$name /name /name$ /name__

2.命名严禁拼音与英文混合,不能直接中文命名.国际通用的拼音除外


说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义.注意,即使纯拼音命名方式也要尽量避免
正例 : alibaba /taobao /youku /hangzhou 等国际通用的名称,可视同英文
反例: DaZhePromotion[打折] / getPingFenByName() [评分] / int 某变量 =3

3.类名使用大驼峰风格,DO/BO/DTO/VO/AO等等除外

类名使用UpperCamelCase风格,但是一下情形例外: DO/BO/DTO/VO/AO/PO/UID等
正例: MarcoPolo /UserDO /XmlService /TcpUdpDeal /TaPromotion
反例: macroPolo /UserDo /XMLService /TCPUDPDeal/TAPromotion

4.方法名,参数名,成员变量,局部变量统一使用小驼峰命名



正例: localValue /getHttpMessage() / inputUserId

5.常量命名全部大写,单词间用下划线隔开,语义尽量完整清楚,不要嫌名字长

正例: MAX-STOCK_COUNT
反例: MAX_COUNT

6.抽象类命名使用Abstract或者Base开头

7.异常使用Exception结尾

8.测试类命名要以它要测试的类的名称开头,以Test结尾

9.类型中与括号紧挨相连来表示数组

正例 定义整形数组 int[] arrayDemo;
反例: 在main参数中,使用String args[]来定义

10.pojo类中的boolean变量都不要加is前缀


pojo类布尔类型的变量,都不要加is前缀,否则八月份框架解析会引起序列化错误.
反例: 定义为基本数据类型Boolean isDeleted的属性,它的方法也是isDeleted(), rpc框架在反向解析的时候,误以为对应的属性名称是deleted,导致属性获取不到,进而抛出异常

11.包名统一使用小写,点分隔符之间仅有一个自然语义的英文单词

包名统一使用小写,点分割之间有且仅有一个自然语义的英文单词,包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式.
正例 : 应用工具类包名为 com.alibaba.ai.util 类名为MessageUtils (此规范参考Spring框架的结构)

12.杜绝完全不规范的缩写,避免望文不知意.


反例: AbstractClass ‘缩写’ 命名成AbsClass : condition ‘缩写’ 命名成 condi ,此类随意缩写严重降低了代码的可阅读性

13.枚举类名带上Enum后缀,枚举成员名称全部大写,单词间用下划线隔开

枚举类命名带上Enum 后缀 ,枚举成员名称需要全部大写.单词间用下划线隔开

说明 枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有的
正例 枚举名字为 processStatusEnum 的成员名称 SUCCESS / UNKNOWN_REASON

14.各层命名规范


Service/dao 层方法命名规约:
1. 获取单个对象的方法用 get做前缀
2. 获取多个对象的方法用list做前缀,复数形式结尾如: listObjects
3. 获取统计值的方法用count做前缀
4. 插入的方法用 save/insert 做前缀
5. 删除的方法用remove/delete 做前缀
6. 修改的方法用update做前缀
7. 切面类用XXXAspect

15.领域模型命名规约

  1. 数据对象: xxxDO ,XXX即为数据表名
    2. 数据传输对象 :XXXDTO, XXX为业务领域相关的名称
    3. 展示对象 XXXVO,XXX一般为网页名称
    4. pojo是DO/DTO/BO/VO的统称,禁止命名XXXPOJO

    (二)常量定义[写完]

    1.不允许任何魔法值(未经预先定义的常量)直接出现在代码中

    反例
    String key = “id#taobao_” + tradeId;
    cache.put(key,value);

    2.在long或者Long赋值时,数值后使用大写的L,不能是小写的l

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

    3.不要使用一个常量类维护所有的常量,要按常量功能进行归类,分开维护

    说明: 大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利用理解和维护
    正例: 缓存相关的常量放在类CacheConsts下,系统配置相关常量放在类ConfigConsts下.

     异常日志[写完]

    (一)异常处理[写完]

    1.Java类库中定义的可以通过预检方式规避的RuntimeException异常不能应该通过catch的方式来处理

    Java类库中定义的可以通过预检方式规避的RuntimeException异常不应该通过cache的方式来处理,比如:NullPointerException,IndexOutOfBoundsException等等
    说明:无法通过预检查的异常除外,比如,在解析字符串形式的数字时,不得不通过catch NumberFormatException来实现
    正例:
    if(obj != null )(…)
    反例:
    try{obj.method();} catch(NullPointerException e){…}

    2.异常不要用来做流程控制,条件控制

    异常不要用来做流程控制,条件控制
    异常设计初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低得多

    3.catch是请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码


    对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理.
    说明: 对大段代码进行 try_catch ,使程序无法根据不同的异常做出正确的应激反应,也不利于定位问题,这是一种不负责任的表现.
    正例:用户注册的场景中,如果用户输入非法字符,或用户名称已经存在,或用户输入密码过于简单,在程序上做出分门别类的判断,并提示给用户.

    4.捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之

    捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者.在外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容./

    5.有try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务,

6.finally块必须到资源对象,流对象进行关闭,有异常也要做try-catch

finally块必须对资源对象,流对象进行关闭,有异常也要做try_catch.
说明: 如果jdk7及以上,可以使用try-with-resources方式

7.不要在finally块使用return

说明: finally块中的return返回后方法结束行执行,不会再执行try快中的return语句.

8.捕获异常与抛异常,必须是完全匹配,或者铺货异常是抛异常的父类.

说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况.

(二)日志规约[写完]

1.应用中不可直接使用日志系统(log4j,logback)中的api,而应依赖使用日志框架.slf4j中的api


应用中不可直接使用日志系统(log4j,Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory:
private static final Logger logger = LoggerFactory.getLogger(Abc.class);

2.日志文件至少保存15天,因为有些异常具备以’周’为频次发生的特点


3.应用中的扩展日志(如打点,临时监控,访问日志等)命名方式:


应用中的扩展日志(如打点,临时监控,访问日志等)命名方式;
appName_logType_logName.log
logType 日志类型,如stats/monitor/access等:
logName: 日志描述.
这种命名的好处:
通过文件名就可以知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找.
正例: mppserver应用中单独监控时区转换异常,如:
mppserver_monitor_timeZoneConvert.log
说明: 推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控.

4.对trace/debug/info级别的日志输出,必须使用条件输出形式或者占位符的方式


对trace/debug/info级别的日志输出,必须使用条件输出形式或者使用占位符的方式

说明: logger.debug(“Processing trade with id :” + id + “and symbol”+symbol);
如果日志级别是warn,上述日志不会打印,但是会执行字符串拼接操作,如果symbol是对象,会执行toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印.
正例:
(条件)建设采用如下方式
if(logger.isDebugEnabled()){
logger.debug(“Processing trade with id :” + id + “and symbol :” + symbol);
}
正例: (占位符)
logger.debug(“Processing trade with id : {} and symbol : {}”,id ,symbol);


5.避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity =false

正例:

6.异常信息应该包括两类信息:案发现场信息和异常堆栈信息,如果不处理,那么通过关键字throws往上抛出

正例: logger.error(各类参数或者对象 toString() + “_”+e.getMessage(),e);

7.谨慎地记录日志,生产环境禁止输出debug日志,有选择地输出info日志.

谨慎地记录日志,生产环境禁止输出debug日志:有选择地输出info日志;如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志
说明:
大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点,记录日志时请思考,这些日志真的有人看么?看到这条日志你能做什么?能不能给问题排查带来好处?

 单元测试[没写]


 安全规约[写完]

1.隶属于用户个人的页面或者功能必须进行权限控制校验

防止没有做水平权限验证就可以随意访问,修改,删除别人的数据,比如查看他人的私信内容,修改他人的订单

2.用户敏感数据禁止直接展示,必须对展示数据进行脱敏

说明: 中国大陆个人手机号码显示为: 158**9119,隐藏中间4位,防止隐私泄露.

3.用户输入的sql参数严格使用参数绑定或者metadata字段值限定,防止sql注入,禁止使用字符串拼接sql访问数据库


4.用户请求传入的任何参数必须做有效性验证

说明: 忽略参数校验可能导致:
page size过大导致内存溢出
恶意 order by 导致数据库慢查询
任意重定向
sql注入
反序列化注入
正则输入源串拒绝服务ReDos
说课:Java代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没问题,但是如果攻击人员使用的是特殊构造的字符串来验证,有可能导致死循环的结果

5.禁止向html页面输出未经安全过滤或未正确转义的用户数据

6.表单,ajax提交必须执行CSRF安全验证

说明 : CSRF(Cross_site request forgery) 跨站请求伪造是一类常见编程漏洞,对于存在CSRF漏洞的应用?网站,攻击者可以实现构造好url,只要受害者用户一访问,后台便在用户不知情的情况下对数据库中用户参数进行相应的修改.

7.在使用平台资源,譬如短信,邮件,电话,下单,支付 必须实现正确的防重放的机制,如数量限制,疲劳度控制,验证码校验.

在使用平台资源,譬如短信,邮件,电话,下单,支付,必须实现,正确的防重放的机制,如数量限制,疲劳度控制,验证码校验,避免被滥刷而导致资源损耗.
说明: 如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其他用户,并造成短信平台资源浪费

 MySQL数据库

(一)建表规约[写完]

1.表达是否与概念的字段,必须使用is_xxxxx的方式命名,数据类型是unsigned tinyint (1表示是 0表示否)

表达是否与概念的字段,必须使用 is_xxx的方式命名.数据类型是unsigned tinyint (1 表示是 ,0 表示否).
说明: 任何字段如果为非负数,必须是unsigned.
注意:POJO类中的任何布尔类型的变量,都不要加is前缀,所有,需要在设置中is_xxx到Xxx的映射关系,数据库表示是与否的值,使用tinyint类型,坚持is_xxx的命名方式是为了明确其取值含义与取值范围.
正例: 表达逻辑删除的字段名 is_deleted , 1表示删除 , 0 表示未删除.

2.表名,字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字

表名,字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字,数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑.
说明: MySQL在Windows下不区分大小写,但是在Linux默认是区分大小写的,因此,数据库名,表名,字段名,都不允许出现任何大写字母,避免节外生枝.
正例: aliyun_admin ,rdc_config ,level3_name
反例: AliyunAdmin ,rdcConfig , level_3_name

3.表名不使用复数名词

表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于DO类名也是单数形式,符合表达习惯.

4.禁止保留字,如desc , range, match ,delayed 等,请参考MySQL官方保留字.


5.主键索引名为pk字段名,唯一索引名为uk字段名,普通索引名则为idx_字段名.

主键索引名为pk字段名;唯一索引命名为uk字段名;普通索引名则为idx字段名.
说明 pl
即 primary key ; uk即 unique key ; idx 即index的简称

6.小数类型为decimal,禁止使用float和double

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

7.如果存储的字符串长度几乎相等,使用char定长字符串类型.

8.varchar是可变长度字符串,不预先分配存储空间,长度不要超过5000

varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索引效率.

9.禁止使用text,blob类型

会浪费更多的磁盘和内存空间.非必要的大量的大字段查询会淘汰掉热数据,导致内存命中率急剧降低,影响数据库性能.

10.禁止使用小数存储货币

使用整数,小数容易导致钱对不上.

11.必须使用varchar(20)存储手机号

  1. 涉及到区号或者国家代号, 可能会出现 + -()
    2. 手机号不会去做数学运算,
    3. varchar 可以支持模糊查询, 列如: like ‘138%’

    12.禁止使用enum,可以使用tinyint代替

  2. 增加新的enum值要做ddl操作
    2. enum的内部实际存储就是整数,你以为自己定义的是字符串?

    13.表必备三个字段: id,gmt_create , gmt_modified

    说明:其中 id必为主键 .类型为bigint unsigned , 单表时自增,步长为1.gmt_create,gmt_modified的类型均为datetime类型,前者现在时表示主动创建,后者过去分词表示被动更新

    14.表的名称最好是加上 ‘业务名称_表的作用’

    比如 alipay_task / force_project trade_config

    15.库名与应用名称尽量一致.

16.如果修改字段含义或对字段标识的状态追加时,需要及时更新字段注释.

17.字段允许适当冗余,以提高查询性能,但是必须考虑数据一致.

字段允许适当冗余,以提高查询性能,但必须考虑数据一致,冗余字段应遵循:
1. 不是频繁修改的字段
2. 不是varchar超长字段,更不能是text字段.
正例: 商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存储类目名称,避免关联查询.

18.单表函数超过500万行或者单表容量超过2GB时,才推荐进行分库分表

如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表

19.合适的字符存储长度,不但节约数据库表空间,节约所有存储,更重要的是提升检索速度.

代码规范[笔记] - 图1

20.必须使用InnoDB存储引擎

支持事务,行级锁,并发性能更好,cpu及内存缓存页优化使得资源利用率更高

21.表必须有主键.列如自增主键

  1. 主键递增,数据行写入可以提高插入性能,可以避免page分裂.减少表碎片提升空间和内存的使用
    2. 主键要选择较短的数据类型,InnoDB引擎普通索引都会保存主键的值,较短的数据类型可以有效的减少索引的磁盘空间,提高索引的缓存效率.\
    3. 无主键的表删除,在row模式的主从架构,会导致备库夯住.

    22.禁止使用外键,如果有外键完整约束性,需要应用程序控制

    解读:外键会导致表与表之间的耦合,update与delete操作都会涉及到相关联的表,十分影响sql性能,甚至会造成死锁,高并发情况下容易造成数据库性能,大数据高并发业务场景数据库使用以性能优先.

    23.必须把字段定义为not null 并提供默认值


    1. null的列使索引/索引统计/值比较都更加复杂,对MySQL来说更难优化
    2. null这种类型MySQL内部需要进行特殊处理,增加数据库处理记录的复杂性;同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多.
    3. null值需要更多的存储空间,无论是表还是索引中每行中的null的列都需要额外的空间来标识
    4. 对null的处理时候,只能采用is null 或者 is not null ,而不能采用 = , in , < , <> , != , not in 这些操作符. 如:
    如: where name != ‘shenjian’ , 如果存在name 为null值的记录,查询结果就不会包含name 为 null 的值的记录.






    (二)索引规约

1.单表索引建议控制在5个以内


2.单索引字段数不允许超过5个


字段超过五个时候,实际上已经起不到有效过滤数据的作用了

3.禁止在更新十分频繁,区分度不高的属性上建立索引

  1. 更新数据会更新 b+树 ,更新频繁的字段建立索引会大大降低数据库性能
    2. ‘性别’ 这种区分度不大的属性,建立索引是没有什么意义的.不能有效的过滤数据,性能与全部扫描类似.

    4.建立组合索引必须把区分度高的字段放前面

    能够更加有效的过滤数据

    5.业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引

    不要以为唯一索引影响了insert速度,这个速度损耗是可以忽略的,但提高了查找速度是明显的,另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生.

    唯一索引可以高效查询,查询的效率非常的高,比如说银行,银行中的银行卡卡号,卡号是中国所有银行的统一发行的,卡号是唯一的数据,不会有重复的,卡号我们就可以定义成一个唯一索引.所有的表都会推荐你做一个特殊的字段索引,一个是主键,另外一个叫业务主键(唯一数据.)这个是推荐的,不是强制的,唯一字段可能会涉及到其它情况,比如说组合索引. 虽然说维护索引会增加你 insert delete update 的效率,但是这种效率的损耗,在500w以下的数据可以忽略掉,但是在查询情况下效率提升非常高,而且还避免了重复问题(因为添加了).

    6.超过三个表禁止join,需要join的字段,数据类型必须绝对一致,多表关联查询时候,保证被关联的字段需要有索引.


    即使双表join也要注意表索引,sql性能

    为什么禁止三张表join,这个是互联网的规定, 一般企业不会出现. 因为表连接越多效率越低,复杂度也越高,



    7.在varchar字段上建立索引时候, 必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可.

    索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索引,区分度会高达90%以上,可以使用count(distinct left(列名,索引长度))/count(*)的区分度来确定.


    8.页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎(solr等等)来解决


    索引文件具有B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引.

    (三)SQL语句[写完]

    1.不使用count(列名)或者count(商量)来代替count(*)

    不要使用count(列名)或count(常量) 来替代 count(),count()是sql92定义的标准统计行数的语法,跟数据库无关,跟null和非null无关.
    说明: count(*)会统计值为null的行,而count(列名)不会统计此列为null值的行.

    2.count(distinct cal) 计算该列除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.不得使用外键与级联,一切外键概念必须在应用层解决

以学生和成绩的关系为例,学生表中的student_id是主键,那么成绩表中的student_id则为外键.如果更新学生表中的student_id,同时触发成绩表中的student_id更新,即为级联更新,外键与级联更新适用于单机地并发,不适合分布式,高并发集群:级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度.

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





孤尽[《阿里巴巴JAVA开发手册》主要作者]:
解释一下这个事情:曾经写过近1200行的存储过程,没有办法断点,下层数据结构只是稍微变动,根本无法找到出错点,只是提示一下说:ERROR:1064啥的。在数据库迁移的时候,由于数据库版本变更,居然存储过程无法执行。另外,业务上需要扩展一下,那就是灾难性的啊。没想到,我觉得毫无争议的这一条,反而成了一个最大的争议点。存储过程只是单机时代的产物,并不适合互联网时代。

吴啊:
任何技术都要分使用场景,阿里这种互联网高并发的场景,很多数据都是分库分表的,而且要求高度可扩展,原则是对db的保护做到最大化,能减少db压力的就减少db压力,尽量把运算逻辑拉到代码里面。存储过程的优点在于封装性好,直接让db进行运算,但是缺点在于难以维护,而且大大增大db压力。所以开发过程中禁止使用存储过程也是阿里多年经验积累出来的。

8.禁止使用存储过程,视图,触发器,event

高并发大数据的互联网业务,架构设计思路是”解放数据库cpu,将计算转移到服务层”,并发量大的情况下,这些功能很有可能将数据库拖死,业务逻辑放到服务层具备更好的扩展性,能够轻易实现”增机器就加性能”. 数据库擅长存储与索引,cpu计算还是上移吧.


9.数据订正(特别是删除,修改记录操作)时,先要select,避免出现误删除,确认无误才能执行更新语句

10.in操作能避免则避免,若是在避免不了,需要仔细评估in后面的集合元素的数量,控制在1000个之内


11.如果有国际化需要,所有的字符存储与表示,均已utf-8编码,注意字符统计函数的区别

说明:
select length(“轻松工作”) ; 返回为12
select character_length(“轻松工作”) ; 返回为4
如果需要存储表情,那么选择utf8mb4来进行存储,注意它与utf-8编码的区别.

12.禁止使用select * , 只获取必要的字段,需要显示说明列属性

  1. 读取不需要的列会增加cpu , io ,net消耗
    2. 不能有效的利用覆盖索引

    13.禁止使用inset into t_xxx values(xxx), 必须显示指定插入的列属性

    容易在增加或者删除字段后出现程序bug

    14.禁止使用属性隐式转换

    select uid from t_user where phone = 13812345678 会导致全表扫描,而不能命中 phone 索引

    15.禁止在 where 条件的属性上使用函数或者表达式


    select uid from t_user where from_unixtime (day) >= ‘2017-02-15’ 会导致全表扫描.
    正确的写法是: select uid from t_user where day>= unix_timestamp(‘2017-02-15 00:00:00’)

    16.禁止使用负向查询,以及%开头的模糊查询

  2. 负向查询条件: not , != ,<> , !< , !> , not in , not like 等,会导致全表扫描
    2. %开头的模糊查询,会导致全表扫描

    17.禁止大表使用join查询,禁止大表使用子查询

    会产生临时表,消耗较多的内存与cpu,极大影响数据库性能.

    18.禁止使用or条件 ,必须改为 in查询


    旧版本 MySQL 的 or 查询是不能命中索引的,即使能命中索引,为何要让数据库耗费更多的cpu帮助实施查询优化呢?


    (四)ORM映射[没写]

    1.在表查一下中,一律不要使用*作为查询的字段列表,需要哪个字段必须明确写明.


    说明:
    1. 增加查询分析器解析成本
    2. 增减字段容易与resultMap配置不一致
    3. 无用字段增加网络消耗,尤其是text类型的字段.

    2.pojo类的布尔属性不能加is,而数据库字段必须加is_,要求在resultMap中进行字段与属性之间的映射

    说明:参见定义POJO类以及数据库字段定义规定,在中增加映射,是必须的.
    在Mybatis Generator生成的代码中,需要进行对应的修改.

    3.不要用resultClass当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义,

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

    4.sql.xml配置参数使用:#{} ,#param# 不要使用${},此种方式容易出现sql注入.

5.不允许直接拿HashMap与Hashtable作为查询结果集的输出

不允许直接拿HashMap与Hashtable作为查询结果集的输出
说明: resultClass=”Hashtable” ,会置入字段名和属性名,但是值的类型不可控.

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


7.不要写一个大而全的数据更新接口,传入为pojo类

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

 工程结构

(一)应用分层[没写]

(二)二方库依赖[没写]



(三)服务器[没写]

 设计规约[没写]




 类命名规范


类名一般上多使用名词,方法名一般多用动词和助动词,这是因为类名要抽象出拥有某种职责的某物, 所以多使用名词。
另一方面,声明接口时,我们一般使用形容词来作为接口的名称(例如:Iterable、Closeable等)。
通过使用形容词,可以较好的注明类所拥有的特性

1.业务逻辑类

即一般所谓的Model层,该层有着各种不同功能的类。
一般性的,给该层的类起名都是Model或是Manager这样的名字,而随着业务的增多,该层也会变的越来越肥大。
实际上在Model层中也有各种各样的层,通过给它们起好名字明确它们的功能,然后组合起来建立起业务逻辑

2.操作DataSource的层

大致上就是拥有某些I/O的基础功能(增删查改、request等)的类,比如说,拥有操作DB逻辑的类、拥有通过
HTTP通信获取Response的类

名称 补充说明
Client 类似HttpClient这样的,在有Server-Client的含义的情况下使用 TwitterApiClient, QiitaApiClient
Gateway 作为访问API时的网关时使用 TwitterTimelineGateway, QiitaAccountGateway
Store,Storage、Registry 访问数据库,在磁盘进行数据持久化时使用 FavoriteSettingStore, DataStorage, ConfigRegistry
Cache 缓存时使用 TimelineCache
Log 日志。或是存储操作历史记录的路径 UsageLog
History 存储历史记录的路径 UsageHistory
Configuration, Preference, Setting 存储设定数据的路径 TimelineConfiguration

有必要的话,可将I/O的基本功能各自分开实现(可提供一个统一管理的接口或是一开始就创建个统一管理的类来操作)

名称 补充说明
Logger 执行日志操作 UsageLogger
Cleaner, Sweeper 清除数据时使用 CacheCleaner, CacheSweeper

3.加工数据的层

名称 补充说明
Filter 筛选数据时使用 TimelineFilter
Extractor 从某个数据中抽出其他数据 MessageExtractor
Formatter 格式化某个数据输出为其他数据 MessageFormatter
Collector 收集数据 AnalyticsDataCollector

4.拉取DataSource的层

取得数据、存储为Cache、然后再将其返回给Controller和Presenter层的层。该层的Model从使用者看来,无需在意获得
的数据是否是从Cache而来。

名称 补充说明
Provider 将上面提到过的DB、http通信、Cache等封装化后的上位层。或是Android中的ContentProvider TwitterTimelineProvider
Manager 管理数据 AccountManager
Loader 读取数据 TimelineLoader
Logger 写日志、或是提供访问Log的抽象层 RecentUsageLogger
Configurator 存储设定的默认值、将某种数据自动的保存到设定 FirstSettingConfigurator
Migrator 处理当版本升级等数据结构发生变化时的逻辑 UserDataMigrator

5.进行异步处理的层

名称 补充说明
Job, Task, Runnable, Executable 统一处理异步操作 UploadJob, MigrationTask
Runner, Executor, Worker 执行被给予的Job和Task UploadJobRunner, MigrationTaskExecutor
Aware 拥有同步操作相关的某些Context,表示在其管理下的接口(Spring Framework有使用) ApplicationContextAware

6.集成访问FrameWork的层

基于Facade模式、提供通向其他的Framework和SubSystem接口的层

名称 补充说明
Facade 实现Facade模式 BoundServiceFacade
Service 将兼容性的实现给封装化,并实现对各种功能的访问的层 ApplicationControllerService
Resolver 根据用户环境进行Routing处理的层 ContentResolver

7.操作View的类

即一般上的Controller层,根据所用的Framework有所不同,大致上一般会命名为如下。
严格来讲,与Presenter有些许的不同,在此将其包含进去

名称 补充说明
Activity Android中使用
Fragment Android中使用
ViewController iOS中使用
Controller MVC中的Controller
Screen.Presenter MVP中的Presenter。Mortar中使用
Window

8.包含UI上的动作的类

抽象特定的操作,并将该操作想执行的处理综合起来的类。也可作为接口名称使用

名称 补充说明
Action 表示操作 SubmitAction, CancelAction
Dispatcher, Handler 接受操作执行处理 SubmitActionDispatcher, UserActionHandler
Listener, Watcher 监视操作。Observer模式的实现名 ClickListener, TextEditWatcher

9.总结

因语言和框架带来的作法和规则的不同,并没有什么一个最好的方法。设计和重构时,在想好了
如何分层后,如何命名也非常重要。在上面我列举了很多,但是直接用有名的设计模式和框架中用到的名字
有可能也比较好。所以尽可能的清楚地起个能把一个类的作用给表现出来的名字吧