软件开发中曾经遇到的那些坑

#development

多年开发经验的程序员比起刚入行的程序员有一个优势就是知道那些地方会容易产生坑,遇到坑的时候如何填坑。入行八年,经历了很多挖坑填坑的过程,在此梳理一下自己遇到的坑以及填坑办法(也可以说是一些开发规范和技巧):

1. 未关闭资源

早些年公司开发尚未应用pmd、findbug等工具对代码进行检查,有些问题并没有明显的反应出来,比如对资源留使用完要及时关闭。 开发过程中遇到同时创建多个流对象的情况,往往只close了其中一个,其他并未close。 资源对象没有close一般不会出现bug,但会造成内存泄漏,影响整个系统运行。所以在开发过程中对资源操作的时候,要多一个心眼,确认使用后有释放资源。当然最好是最后能使用pmd、findbug等工具对代码进行扫描一下。

2. SQL中使用造成全表扫描的where子句

一般查询where语法涉及到的查询字段都会创建相应的索引,以提高查询过滤速度。 但以下where子句的使用可能会造成数据库不会使用索引过滤,而是使用全表扫描的方式。

2.1. 使用空值判断:

比如: where name is null

应该尽量避免字段值为空,字段初始化的时候最好给一个默认值。比如name初始化为“NONAME”,上面的查询语法改为 where name = ‘NONAME’.

2.2. 使用不等于判断

比如:where name != ‘tom’

不等于条件会造成全表扫描,应尽量避免使用!

2.3. 使用or条件

比如:where name=’tom’ or age=20

如果一个字段有索引,一个字段没有索引,将导致全表扫描。如果是必要的条件,建议将两个条件分拆为两个查询中并使用union all的方式合并两个结果集。

2.4. 使用in或者not in

比如: where name in (‘tom’,’jerry’,’bob’)

in和not in可能会造成不会使用索引,如果是in里面的是一个子查询,见一个改为用exists子句关联。

2.5. 使用like语法

比如:where name like ‘%tom%’

这样的语句对大数据量的表需尽量避免使用,如果业务必须,可考虑使用其他全文索引的方式。

2.6. 对条件字段进行函数操作

比如: where datediff(day,create_time,’2016-11-05’) = 0

避免对条件字段进行函数操作,改为变换条件条件的方式达到想要的效果.上面一句可以改为: where create_time >= ‘2016-11-05’ and create_time< ‘2016-11-06’

3. 大批量数据操作

经常遇到这样的需求: 遍历某一个表记录,进行某一个处理。没经验的工程师就采用select all的方式查出所有遍历处理。 如果数据量比较小是没有问题的,数据量很大的时候,现代的框架直接读取所有记录加载到内存,直接把内存撑爆了。如果可以游标的方式处理,则尽量使用游标遍历的方式。不行则使用批次的方式,及一次只处理一部分记录,处理完这一批次再处理下一批次。批次处理另外就涉及到要顺序处理或者说添加处理标记,避免下一批次处理时还对之前处理过的记录进行处理。如果是多线程处理又和单线程处理不一样,则需考虑更多。一般可以一开始将记录分段交个不同的线程处理;也可以由统一的一个线程负责划分记录段,交个线程池处理,线程池中的每一个线程需要处理的时候,就去领一个记录段进行处理。

4. 事务控制的坑

4.1. 控制层多个业务逻辑未包含在一个事务中

MVC架构中,控制层controller是没有事务的,如果在controller中调用多个服务层的设计数据变更的方式,这些方法的执行是在各自事务中进行的,如果没有发生异常则不会有问题,如果第二个调用或靠后的调用发生异常,则只会回滚当前的事务,之前已经执行完的服务调用的事务则不会回滚,造成数据不一致问题。 这种情况应该把多个服务调用的逻辑提到一个服务方法中,确保都使用统一一个事务。

4.2. 无事务控制的第三方调用未放到整个逻辑调用的最后步骤

一个服务方法,包含数据库保存以及第三方接口调用,但第三方调用没有回滚方法。如果把第三方调用放在第一步,第三方调用成功,但数据库保存失败异常回滚,但第三方调用却无法回滚。 这时应先保存数据库,再最后调用第三方。数据库保存成功,但第三方调用失败异常回滚,也会使之前的数据库操作回滚。

4.3. 批量业务包含事务

批量业务涉及大量数据记录的操作,如果整个批量放在一个事务中,会产生对大量记录的锁,并且会锁住较长的时间。这可能会造成其他业务操作等待很久或操作失败的情况。 一般批量业务不应该包含事务,而是单笔操作的时候添加事务支持即可。

5. 不断在旧代码方法中添加新业务逻辑

业务需求变更每次提出一点修改,很多工程师都只是为了单纯去实现这个需求,直接在原有方法中添加相关的逻辑。久而久之,一个方法变得极其冗长,牵涉的逻辑繁多。如果发生了问题,维护工程师要去理解这些代码极其困难,就算是原来开发的工程师也可能看不懂。维护的成本成倍增加,这无疑是一个很大的坑。应该要求工程师对代码方法及时做重构,每一个代码方法的行数进行一定限制,并用相应的代码检查工具进行检查,避免代码混杂的情况发生。

6. 没有注释的代码

工程师阅读没有注释的代码,有可能出现盲人摸象的情景,每个人对代码的理解都不一样,导致修改的方式也不一样或不完整。发生问题的时候就会抱怨: 你代码都没有注释,谁知道你这还有这个逻辑? 应该要求工程师对涉及业务关键逻辑的代码都添加注释,并靠有经验的人员对代码进行评审。代码注释也不宜太多,如果代码全是注释等于没有注释。

05 Nov 2016,gelnyang