第三天

            北京有句“金三银四”来描述三四月份求职的火热,技术岗位比较好招聘,今天开始讲一讲招聘的问题。

            现在比较流行微服务架构,小公司至少要做到SOA架构,敏捷开发也是当下比较火热的开发流程,结合以上两点,招聘工作重点在后端开发岗位上,我们选择后端语言为java,招聘需求大概为:

            1、计算机科学或相关专业毕业,3-5年工作经验。


            2、熟练掌握java语言,多线程、java集合类的使用。 


            3、熟练掌握spring、ibatis等主流开框架,有独立搭建项目骨架,以及框架之间集成的能力。 


            4、熟悉消息通信常用的RPC框架,dubbo,activeMQ等,对java NIO有一定的原理性的了解。 


            5、熟悉常用的java设计模式,不过度使用的情况下,使代码架构简洁清晰并有可扩展性、可维护性。


            6、熟练使用maven项目骨架管理工具,以及git代码管理工具,熟练使用IDEA。


            7、熟练使用Mysql数据库,对分库分表的开源组件有一定的了解,并有针对业务场景有设计数据库结构关系的能力。 


            8、熟练使用linux系统,对Linux基本的命令熟练使用,可以再Linux服务器独立部署和维护应用。 


            9、熟练使用spring boot/cloud优先。


            10、熟练使用Netty4框架优先。



            除了优先项,这基本是java开发的标配了,特殊需求另说。


            前端招聘需求:


            1. 熟练运用 JavaScript6 与 HTML5 、 CSS3 、Ajax
            2. 熟悉模块化、前端编译和构建工具
            3. 深入理解 react 技术栈,包括但不限于 redux、graphql、react-native 等
            4. 对js框架应用(如jQuery/Zepto.js中的一种)能熟练使用及再开发;
            5. 深入理解异步编程模型
            6. 熟悉 Web 安全相关知识,并能使用相关技术防范安全漏洞
            7. 熟练使用 mongodb、redis者优先
            8. 有极强的技术敏感性和学习能力者优先


            


            测试工程师是个重要的岗位,高级的测试人员可以很好的提高开发的编码能力,招聘需求:


            1.正规院校计算机软件相关专业,本科以上学历;
            2.3年以上测试工作经验,具备丰富的测试自动化、业界测试技术等方面的实战经验;
            3.精通自动化测试思想、技术、发展趋势,熟悉业界自动化现状


                     熟悉业界商业开源的自动化测试框架工具并能熟练应用和二次开发;
            4.精通一种脚本语言(如Java, Shell、Ruby、Python等), 熟悉linux操作系统及相关的命令


                     熟悉至少一种应用服务器的配置(如tomcat, weblogic等);
            5.熟悉Jenkins/Hudson的配置和操作,熟练使用Eclipse/Idea、maven、svn等


                     精通Junit/TestNG等相关的自动化测试框架;
            6.熟悉至少一种单元测试框架(如Jmockit, mockito, EasyMock等), 有相应的实战经验;


            其他岗位忽略。

    Tips:我们选用前后端分离的开发模式,重后台,侧重前端,后台通过springboot/cloud快速搭建项目,前端使用VUE等完全独立渲染页面。

        重点讲一下面试中的情况与问题。

        这两年你手里的招聘工作没有断过,重点在招聘架构师和一些带团能力强的岗位,比例技术经理,合适的人才还是还是可遇不可求的,双方时间上不冲突,共同的理念,也是比较看缘分吧。

        新公司招聘重点在一线coding的人员上,面试过程中我更习惯面试一些理念性的东西,比如举例一些场景让应聘者提供多种解决思路。尤其带过团队的应聘者是比较加分的,解决问题的能力会强一些。

        另外的一些重点在学习能力上,更多的关心应聘者怎么看待技术更新,还有应聘者的稳定性。

        重点:

                简历水分,技术行业有太多太多浮躁的年轻人,不知何时有了频繁跳槽加薪的陋习,很多人项目只参与了一小部分,就沾沾自喜、不可一世,面试过程中问到稍微深一些的技术点就晕了,我理解经验对面试的重要性,但是还是要做好十足的准备的;另外有很大一部门培训机构的培训生,参加培训是好事,但十之有九在伪造工作经历,这样就算面试通过也会造成工作上无法胜任,更何况基础不够扎实,没有真实开发经验,是很危险的开发,我个人很欣赏抽空参与培训的人,但做事要踏踏实实。



附一份JAVA技术规范,可以结合阿里技术规范做自己框架的调整,仅供参考:


 

 

 

 

开发规范

 

1.  代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束

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

3.  类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:(领域模型的相关命名)DO / BO / DTO / VO 等

4.  方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式

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

6.  抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾

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

8.  POJO 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误

9.  所有的 POJO 类属性必须使用包装数据类型。

10. RPC 方法的返回值和参数必须使用包装数据类型。

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

12. 各层命名规约:

a)  Service/DAO 层方法命名规约

1)  获取单个对象的方法用 get 做前缀。

2)  获取多个对象的方法用 list 做前缀。

3)  获取统计值的方法用 count 做前缀。

4)  插入的方法用 save(推荐)或 insert 做前缀。

5)  删除的方法用 remove(推荐)或 delete 做前缀。

6)  修改的方法用 update 做前缀。

b)  领域模型命名规约

1)  数据对象:xxxDO,xxx 即为数据表名。

2)  数据传输对象:xxxDTO,xxx 为业务领域相关的名称。

3)  展示对象:xxxVO,xxx 一般为网页名称。

4)  POJO 是DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO

13. 所有的局部变量【推荐】使用基本数据类型。

14. 定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值。

15. 任何运算符左右必须加一个空格,运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号、三目运行符等。

16. if/for/while/switch/do 等保留字与左右括号之间都必须加空格

17. 单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:

1)        第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。

2)        运算符与下文一起换行。

3)        方法调用的点符号与下文一起换行。

4)        在多个参数超长,逗号后进行换行。

5)        在括号前不要换行

18. 方法参数在定义和传入时,多个参数逗号后边必须加空格

19. 所有的覆写方法,必须加@Override 注解

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

21. 序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值

22. 不能使用过时的类或方法

23. Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals

24. 所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。说明:对于 Integer var=?在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。

25. 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中

26.    POJO 类必须写 toString方法。使用 IDE 的中工具:source> generate toString 时,如果继承了另一个 POJO 类,注意在前面加一下super.toString。

说明:在方法执行抛出异常时,可以直接调用 POJO 的 toString()方法打印其属性值,便于排查问题

27.    当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起,便于阅读

28.    类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法

29.    setter 方法中,参数名称与类成员变量名称一致,this.成员名=参数名。在 getter/setter 方法中,尽量不要增加业务逻辑,增加排查问题的难度

30.    循环体内,字符串的联接方式,使用 StringBuilder 的 append 方法进行扩展

31.    final 可提高程序响应效率,声明成final 的情况:

1)        不需要重新赋值的变量,包括类属性、局部变量。

2)        对象参数前加 final,表示不允许修改引用的指向。

3)        类方法确定不允许被重写

32.    类成员与方法访问控制从严:

1)        如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。

2)        工具类不允许有 public 或 default 构造方法。

3)        类非 static 成员变量并且与子类共享,必须是 protected。

4)        类非 static 成员变量并且仅在本类使用,必须是 private。

5)        类 static 成员变量如果仅在本类使用,必须是 private。

6)        若是 static 成员变量,必须考虑是否为 final。

7)        类成员方法只供类内部调用,必须是 private。

8)        类成员方法只对继承类公开,那么限制为 protected。

33.    关于 hashCode 和 equals 的处理,遵循如下规则:

1)        只要重写 equals,就必须重写 hashCode。

2)        因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法。

3)        如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals。

正例:String 重写了 hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用

34.    ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList; 说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上

35.    在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均产生 ConcurrentModificationException 异常

36.    使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()。使用 toArray 带参方法,入参分配的数组空间不够大时,toArray 方法内部将重新分配内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为 null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致

37.    使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常

38.    不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁

39.    集合初始化时,尽量指定集合初始值大小。说明:ArrayList 尽量使用 ArrayList(int initialCapacity) 初始化。

40.    使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key 所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.foreach 方法

41.    高度注意 Map 类集合 K/V 能不能存储 null 值的情况,如下表格:

集合类

Key

value

super

说明

Hashtable

不允许为null

不允许为null

Dictionary

线程安全

ConcurrentHashMap

不允许为null

不允许为null

AbstractMap

分段锁技术

TreeMap

不允许为null

允许为null

AbstractMap

线程不安全

HashMap

允许为null

允许为null

AbstractMap

线程不安全

 

42.    利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的 contains 方法进行遍历、对比、去重操作

43.    获取单例对象需要保证线程安全,其中的方法也要保证线程安全。说明:资源驱动类、工具类、单例工厂类都需要注意

44.    创建线程或线程池时请指定有意义的线程名称,方便出错时回溯

45.    SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类,如果是 JDK8 的应用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar, DateTimeFormatter代替Simpledateformatter,官方给出的解释:simple beautiful strong immutable thread-safe

46.    高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁

47.    对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁

48.    多线程并行处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题

49.    避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一 seed 导致的性能下降。Random 实例包括 java.util.Random 的实例或者 Math.random()实例,在 JDK7 之后,可以直接使用 API ThreadLocalRandom,在 JDK7 之前,可以做到每个线程一个实例

50.    volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题,但是如果多写,同样无法解决线程安全问题。如果是 count++操作,使用如下类实现: AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推 荐使用 LongAdder 对象,比AtomicLong 性能更好(减少乐观锁的重试次数)

51.    HashMap 在容量不够进行resize 时由于高并发可能出现死链,导致 CPU 飙升,在开发过程中注意规避此风险

52.    ThreadLocal 无法解决共享对象的更新问题,ThreadLocal 对象建议使用 static 修饰。这个变量是针对一个线程内所有操作共有的,所以设置为静态变量,所有此类实例共享此静态变量 ,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象(只要是这个线程内定义的)都可以操控这个变量

53.    在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有

54.    在 if/else/for/while/do 语句中必须使用大括号,即使只有一行代码,避免使用下面的形式:if (condition) statements

55.    除常用方法(如 getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?

56.    方法中需要进行参数校验的场景:

1)        调用频次低的方法。

2)        执行时间开销很大的方法,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,那得不偿失

3)        需要极高稳定性和可用性的方法。

4)        对外提供的开放接口,不管是 RPC/API/HTTP 接口。

5)        敏感权限入口。

57.    方法中不需要参数校验的场景:

1)        极有可能被循环调用的方法,不建议对参数进行校验。但在方法说明里必须注明外部参数检查。

2)        底层的方法调用频度都比较高,一般不校验。毕竟是像纯净水过滤的最后一道,参数错误不太可能到底层才会暴露问题。一般 DAO 层与 Service 层都在同一个应用中,部署在同一台服务器中,所以 DAO 的参数校验,可以省略。

3)        被声明成 private 只会被自己代码所调用的方法,如果能够确定调用方法的代码传入参数已经做过检查或者肯定不会有问题,此时可以不校验参数。

58.    所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。说明:对子类的实现要求,或者调用注意事项,请一并说明。

59.    所有的枚举类型字段必须要有注释,说明每个数据项的用途

60.    对于注释的要求:第一、能够准确反应设计思想和代码逻辑;第二、能够描述业务含义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路;注释也是给继任者看的,使其能够快速接替自己的工作

61.    后台输送给页面的变量必须加$!{var}——中间的感叹号。说明:如果 var=null 或者不存在,那么${var}会直接显示在页面上

62.    注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。

63.    获取当前毫秒数 System.currentTimeMillis(); 而不是 newDate().getTime(); 说明:如果想获取更加精确的纳秒级时间值,用 System.nanoTime()。在 JDK8 中,针对统计时间等场景,推荐使用 Instant 类

64.    不要捕获 Java 类库中定义的继承自 RuntimeException 的运行时异常类,如: IndexOutOfBoundsException / NullPointerException,这类异常由程序员预检查 来规避,保证程序健壮性。 正例:if(obj !=null) {...}

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

66.    不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句

67.    防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:

1)        返回类型为包装数据类型,有可能是 null,返回 int 值时注意判空。反例:public int f(){ return Integer 对象}; 如果为 null,自动解箱抛 NPE。

2)        数据库的查询结果可能为 null。

3)        集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。

4)        远程调用返回对象,一律要求进行 NPE 判断。

5)        对于 Session 中获取的数据,建议 NPE 检查,避免空指针。

6)        级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。

68.    避免出现重复的代码(Don’t Repeat Yourself),即 DRY 原则

69.    应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。 import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(Abc.class);

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

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

< logger name="com.taobao.dubbo.config"additivity="false" >

72.    可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。注意日志输出的级别,error 级别只记录系统逻辑出错、异常等重要的错误信息。如非必要,请不要在此场景打出 error 级别

73.    谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志

74.    表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。

75.    禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字

76.    唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。说明:uk_ 即 unique key;idx_ 即 index 的简称。

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

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

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

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

81.    字段允许适当冗余,以提高性能,但是必须考虑数据同步的情况。冗余字段应遵循:

1)        不是频繁修改的字段。

2)        不是 varchar 超长字段,更不能是 text 字段。

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

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

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

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

86.    如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。正例:where a=? and b=? order by c; 索引:a_b_c

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

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

88.    SQL 性能优化的目标:至少要达到range 级别,要求是 ref 级别,如果可以是 consts 最好。

说明:

a)        consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。

b)       ref 指的是使用普通的索引(normalindex)。

c)        range 对索引进行范围检索

89.    利用延迟关联或者子查询优化超多分页场景。说明: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

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

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

92.    当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为 NULL,因此使用 sum()时需注意 NPE 问题。正例:可以使用如下方式来避免 sum 的 NPE 问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;

93.    使用 ISNULL()来判断是否为 NULL 值。注意:NULL 与任何值的直接比较都为 NULL。

说明:

1)        NULL<>NULL 的返回结果是 NULL,而不是 false。

2)        NULL=NULL 的返回结果是 NULL,而不是 true。

3)        NULL<>1 的返回结果是 NULL,而不是 true。

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

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

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

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

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

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

100.隶属于用户个人的页面或者功能必须进行权限控制校验。 说明:防止没有做水平权限校验就可随意访问、操作别人的数据,比如查看、修改别人的订单

101.用户敏感数据禁止直接展示,必须对展示数据脱敏。 说明:查看个人手机号码会显示成:158****9119,隐藏中间 4 位,防止隐私泄露

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

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

说明:忽略参数校验可能导致:

l page size 过大导致内存溢出

l 恶意 order by 导致数据库慢查询

l 任意重定向

l SQL 注入

l 反序列化注入

l 正则输入源串拒绝服务 ReDoS

说明:Java 代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没有问题,但是如果攻击人员使用的是特殊构造的字符串来验证,有可能导致死循环的效果。

104.所有的double进行加减乘除操作必须用DoubleUtils.tworound()

105.所有的Long类型进行数值对比的时候,必须加上longValue后对比=。

106.上传文件一定要限制,只允许平台允许的正常文件格式

107.每个java原文件,ctrl +shift+ o 去掉多余的引入包

108.sprng mvc 接收参数数值类型要用long或者int接收,不要用string

109.html使用<script><script> 一定要成对使用,不能使用

<script src="${ctx}/javascript/jquery.form.js"type="text/javascript" />这种方式

110.随机类不使用java.util.Random使用java.security.SecureRandom类

111.在循环语句结构中使用StringBuffer代替String进行拼接