kotlin后端Code review
一、性能问题(代码效率)
1、string
1)、string频繁操作,影响性能。
原理:每次对字符串对象进行变更操作,都需要重新分配内存空间,然后将原有的字符串内容复制到新的内存空间中。 这就会导致频繁的内存分配和复制操作,从而降低应用程序的性能。详细说明见文章:Unity性能优化-字符串
2)、字符串拼接:
不同于Java,Kotlin支持字符串内嵌套表达式功能,不需要再进行字符串拼接!可以使用字符串内嵌套 ${} 这种表达式。
2、查询的性能
1)、判断查询结果
判断是否为空时在数据库count结果条数。不要去用isEmpty()方法判断。
2)、禁止毫无意义的重复查询。
原理:每条都遍历查库,而建立session访问数据库较耗时,数据库交互就要2秒,加上其他逻辑,大量查询拉低数据库性能。详情见:避免在for循环中使用sql语句
3)、where条件
where条件字段拼写错误,会导致条件无法命中而查出大量数据。
4)、指定所需列
大于20个以上字段的多字段表,查询,更新时应指定所需列。
5)、分页
数据量达到3000条以上的查询结果时,采用分页。原理:将所有数据分段展示给用户,用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止。详情见:分页技术原理与实现(一)——为什么要进行分页及怎么分页
6)、针对移动端向下滑动查询的场景,应使用分片查询。
(1)、向下滑动查询,
类似于ajax动态加载,不停向下滑动,不停加载信息。
(2)、分片的原理:
分片是一种与水平分区模式,这种模式是将一个表的行分为多个不同的表(称为分区)的实践。每个分区都有相同的架构和列,但行完全不同。并且,每个分区中保存的数据都是唯一的,并且与其他分区中保存的数据无关。
数据库将信息存储在由列和行组成的多个数据集中。数据库分片将单个数据集拆分为分区或分片。每个分片都包含独特的信息行,可以跨多台计算机(称为节点)单独存储这些信息。所有分片都在单独的节点上运行,但共享原始数据库的架构或设计。 详情见:什么是数据库分片?
elasticsearch 分片(Shards)的理解
7)、数据库和应用层,各自负责不同业务逻辑
去重,排序,分组,top等操作,都应该在数据库中处理,而不应该在应用层处理。原理:简单的放在数据库,复杂的放在程序里。详情见:业务逻辑写在数据库还是自身应用程序?
3、插入的性能
1)、避免通过循环来对批量数据插入,更新,删除等操作。
※※※ 在循环中,禁止使用crud!!!
4、流操作
1)、什么是流操作
流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以“流”的方式进行。设备可以是文件,网络,内存等。详情见:深入理解流,什么是流?
2)、使用kotlin的关键字use来处理。
其中封装了流的标准操作,包括流的关闭。
5、对象的创建
1)、避免频繁的创建对象。
在整个应用中只需要存在一个实例的类应该使用单例模式。
二、代码规范
1、参考kotlin官方文档规范:
三、controller层
1、controller层代码都应写在rest软件包子目录内。
2、名称拼写问题
1)、创建的软件包名称应为全小写,
其中的controller类名应与软件包拼法一致,但采用驼峰命名,且以Controller结尾。如包命为part,类名应为PartController。
2)、接口路径应为全小写。
如:@RequestMapping(value = [“/api/adjacentangle”]),其中value中的值应为全小写。词组用减号’-'分割。
3、接口的入参,异常处理
返回统一使用"公司名+Toolkit.restResult(currentClass, args)" 处理。 不应直接返回Any类型。
4、controller类中应尽量简单,不应有逻辑处理。
5、超过四个入参的接口应尽量采用DTO对象,通过POST调用。
6、同一个软件包内只能有一个controller类
但软件包中可以嵌套软件包。
7、类型的定义应准确合理清晰。
如类型只有true和false,应定义为布尔类型。反例:“TRUE”,“true”,"Y"等。
四、entity
1、数据库的映射类建立在entity包下
entity包下无需嵌套软件包,直接放置映射类。
2、指向只读数据库的情况
对数据实时性要求不高的数据表,应指向只读数据库,readonly = true。
3、表字段应有备注
将其中文语意写在label_cn中,如label_cn = “资料说明”。
五、service层
1、关于注解@Transactional
注解@Transactional应尽量避免放到类上,尽量避免在查询中使用该注解,事务控制下的方法执行时间越短越好。
2、重复的代码应尽量抽象共用方法调用。
3、应尽量避免if…else…嵌套,注意代码风格。
4、多线程应采用注解@Async处理
该注解用法简单,且无需关注线程池的配置。
5、redis缓存应统一用@CacheAble处理
该注解用法简单,且key在redis中会自动分类。
6、变量的命名应有意义且拼写正确
尽量使用不可变val定义变量。尽量使用不可变集合代替可变集合。
7、禁止在foreach与map循环操作中对元素进行 remove与add操作。
8、数据校验应使用工具类"公司名+Toolkit.require"
异常的抛出应使用 “公司名”+Toolkit.error。
六、注释规范
1、注释力求精简准确,表达到位。
1)、多行注释
类,方法,类属性中的注释采用多行注释 /***/,注意格式对齐。
2)、单行注释
方法内部单行注释时,应在被注释语句上另起一行,采用//注释。多行注释采用 /***/。
3)、所有的枚举字段都应该有注释。
七、格式规范
1、概念相关的代码应该放到一起,不相关的应该有适当空行。
2、注释与代码之间应该有适当空行
留有适当空行表示该注释是解释以下代码的, 如:
//获取当前用户同帐号
val agentId = "0"
val agentInfo = at.findAgentId(agentId)
val userId = os.getUserInfo(code, agentInfo.appNo)
//发放用户登录凭证,用于AJAX请的身份验证
val userTicket = os.userAuthTicket
//获取消息消息原始跳转的URL
val linkUrl = ct.getLinkUrl(state.toInt())
3、每行代码的长度
尽量不超过idea等编译器标示的规范竖线。