Java 规范与避坑常见示例及说明

6 篇文章 0 订阅
2 篇文章 0 订阅

 

1. Git 使用避坑指南

1)切分支出错

master 主分支,即生产版本,xx_test 分支对应测试环境分支,请基于 xx_test 分支拉功能分支开发。比如两个新需求同时开发,项目管理人员此时需基于 xx_test 拉出两个功能分支,分别是 feature-a 分支和 feature-b 分支。开发人员检出对应的功能分支,并在其上开发。

粗心的开发人员忘了切换分支,直接在检出的 master (xx_test 分支)开发、合并或提交。容易参数代码混乱。

2)测试完过早合并至 master 主分支

如 feature-a 分支 和 feature-b 分支对应两个功能需求,需求 feature-b 功能先开发测试完,然后合并至 master 主分支,这时产品和项目经理确定发版内容为 feature-a 分支功能,由于开发人员疏忽,导致 feature-b 也上线了,容易出现生产事故。

开发完合并至 xx_test 分支,测试环境测试完成,待发版时,再合并到 master 主分支。

3)merge 代码冲突解决不当

feature-a 分支 或 feature-b 分支开发完成,git merge 到 xx_test 分支时,如果涉及其他开发人员提交的内容,且不确定,错误删除了别人的代码。

请与相关需求对应的开发人员一同解决代码冲突问题。

4)遵循一个分支只做一件事

feature-a 分支只开发新的需求 a,此时开发人员看到某个方法觉得编码不太规范,顺手优化一下,结果优化完,没有和测试人员或项目经理说,等上线完,线上出现问题,为时已晚。如果有修改非新需求的代码,请告知测试或产品进行回归测试相关系统的一切功能。

建议优化代码时,另拉出一个 optimize-a 分支进行优化或重构。

5)同一个功能开发人员 commit 多次,不利于阅读,合并提交记录

为了使分支提交记录更清晰,需要合并多次提交为一次提交。

①第一种方式交互式,主要涉及的 git 命令如下: 

# 得到需要合并提交记录的前一个提交记录的 commitId
git log  
# 进入交互式修改,以其中一个 pick 为基准,其他需要合并的 commitId 前的pick 修改为 squash(简写 s),保存修改并退出即可
git rebase -i [commitId]  
# 推送至远程仓库
git push 
# 或强制推送至远程仓库(谨慎使用)
git push -f  

②第二种方式回滚,主要涉及的 git 命令如下:

git log
# 比如合并前三个,commitId 是前第四个的提交记录
git reset [commitId]  
# 添加至暂存区
git add .
# 提交至本地仓库
git commit -m “commit msg”
git push 或 git push -f

功能分支的代码合并至 master 分支后,提交记录更合理清晰,方便其他开发人员了解或是 code review。

2. 数据库避坑指南

1)业务上唯一特性的字段(或组合字段)请建立唯一键约束

避免出现诡异现象或是导致业务上出现错误,增加排查的难道或是编码复杂。

很多人认为,保证唯一性,“先查后插”。其实高并发场景下,如果没有进行同步操作,两个事务同时开启,查数据库没有,然后导致数据库插入了两条重复的数据(即产生垃圾数据)。

可能的影响有:Dao 层出现 sql 执行异常,业务逻辑层处理与实际不符等等。

2)delete 操作时请注意带上 where 条件

开发人员,在写 delete 语句时,请先带上 where 条件查询数据库,看数据是否符合删除的逻辑,然后再写 delete 语句删除相应条件下的垃圾或是废弃数据。

delete ... where条件很重要

3)由于业务需要某旧表新增字段,设置 NOT NULL 请谨慎!

可能影响其他接口业务逻辑插入该表,没有插入非空字段,导致线上系统接口异常。

如果新增字段为空,请检查相关接口,或是设置默认值。

4)新增字段考虑是否创建索引

大多数人在建新表时,有意识的新增索引,但是在旧表新增字段时,却忘记创建索引。后期因为数据量大或是并发高,导致数据库性能下降。

如果新增字段是 where 查询条件,请考虑创建索引或是组合索引,避免出现数据库查询性能问题

5)使用 insert into 语句注意字段对应关系

强制使用 insert into table_name (field1, field2, ...) values (value1, value2, ...);

禁止使用 insert into table_name values (value1, value2, ...);

如何新增字段,可能导致其他接口服务报错(sql 语法错误)

6)分页查询条数限制

在数据库分页查询时,mysql 中 select * from table_name limit m,n; 注意对 n 参数校验,防止每页查询的数据量过大,导致内存溢出;oracle 中 select * from (select * from (select rownum rn, t1.* from (select * from page_table_name) t1) where rownum <= currentPage * pageSize) where rn > (currentPage - 1) * pageSize; 注意对 pageSize 参数校验,防止每页查询的数据量过大,导致内存溢出。 

分页查询需对每页条数参数校验,防止发生线上系统出现OOM

7)避免数据库长事务发生

批量入库操作时,循环结束后再提交可能引起长事务发生,注意每多少条 sql 执行一次提交;多个 sql 执行顺序、执行时机按业务逻辑和性能调到最优。

长事务易触发数据库机制导致kill进程或是数据库阻塞等,合理事务范围及事务耗时。

8)大表创建索引或 DDL 避免高峰期执行,或是升级停库时执行

大表创建索引或是执行 DDL 时,引起数据库表锁表,对高峰期业务接口响应影响较大。

创建索引或执行 DDL 时停机执行。

9)where 条件少写 (field != 'X' 或者 field <> 'X')

可能会出现结果集不符合预期。比如数据库字段 field 不是 NOT NULL,where 条件如果是 field != 'X' 此时查询的结果集不全(不包含 is null),所以 where 条件应该是 field is null or field <> 'X'。

一般建议创建新表定义字段时,添加 not null 约束。另外查询条件不建议使用 != 或 <>,这样索引可能失效,尽量使用等值或范围查询。

10)单表或多表关联分页

如果执行计划出现 SORT ORDER BY,一般这种分页查询的 sql 是有问题的。

利用索引的有效性,等值查询,创建组合索引(等值过滤条件与排序字段优先组合、非等值过滤条件放在后面,其中等值过滤条件能过滤掉大量数据的放在最前面)等;

多表关联分页,走嵌套循环,如果驱动表返回的数据是有序的,那么关联之后的数据集也具备有序性。

让参与排序的表作为嵌套循环的驱动表,其他关联表对应的连接列创建索引。如果存在外连接,选择主表列作为排序列。语句中不能存在 distinct、group by、max、min、avg、union、union all。

11)oracle 分页 sql 写法误区

select * from (select t.*, rownum rn from(select * from tmp) t) where rn >= 1 and rn <= 10; 

上面的分页查询 sql 是错误的写法。

这种写法没有使用到 oracle 的 COUNT STOPKEY 特性,即获取到分页的结果集后 sql 立即停止运行。

正确的写法应该如下:

select * from (select t.*, rownum rn from (select * from tmp) t where rownum <= 10) where rn >= 1;

走索引排序。使用 COUNT STOPKEY 特性。如果有过滤字段,可以考虑组合索引,如果过滤条件能够过滤大部分数据,排序列可以不包含在索引中。

3. Java 避坑指南

技术原理理解不到位带来的性能问题或坑。可参考《阿里巴巴Java开发手册》

举例说明:

1)创建 ArrayList 或 HashMap 时,合理设置集合初始化容量

避免集合扩容带来的性能消耗。

集合都有默认初始化容量和扩容机制,多次扩容会引起性能问题或接口响应变慢等。

2)谨慎使用 ArrayList 集合的 subList 方法

subList 方法返回的子类是 ArrayList 内部类 SubList,是原 ArrayList 的地址引用(和数据库视图有点类似)。

对subList返回的结果操作会反映在原ArrayList集合上,而对原集合进行结构变化,会触发并发修改异常

3)合理使用 Executors 构造线程池,最好使用 ThreadPoolExecutor(7参)构造

避免 Executors 构造的无限线程或是无界队列造成 OOM 异常。

根据任务是 I/O 密集性还是 CPU 密集性,合理设置线程池参数(核心线程数、最大线程数、任务队列、拒绝策略等),使线程池发挥最大功效。

4)开启事务时,注意事务隔离级别、回滚条件、传播策略、事务超时设置

MySQL 数据库默认事务隔离级别是RR(可重复读);Orcale 数据库默认事务隔离级别是RC(读已提交)。针对RC,会出现幻读,不可重复读。事务回滚条件设置(捕获程序异常时注意)。传播策略默认是当前有事务直接加入该事务,没有事务新建事务。设置合理的事务超时时间(数据库管理系统内置有相关的参数设置)。

养成好的习惯很重要!

举例说明:

1)开发前没有仔细梳理需求、绘制 UML、时序图、活动图的习惯(针对开发人员、技术经理);

2)开发时没有自我 code review 的习惯(针对开发人员、技术经理);

3)测试时没有看 error log 的习惯(针对开发人员、测试人员);

4)上线前没有检查各种 properties file 的习惯(针对开发人员、技术经理);

5)上线过程中和上线后没有关注线上系统日志和系统监控的习惯(针对开发人员、项目经理)。

编码规范很重要!可参考《阿里巴巴Java开发手册》和《Google 开发编码规范》

举例说明:

1)int a,b,c = 0; 命名不规范,debug 不方便(建议定义变量时一行一个);

2)定义变量,作用域最小化,遵循就近原则,对象引用范围最小化(比如:静态成员变量中引用了其他类对象);

3)合理使用强引用、弱引用、软引用、虚引用。

4)规范日志记录,使用占位符(减少拼接字符串的性能消耗);

不规范:log.info(“programme_id:” + programmeId + “, appl_no:” + applNo);

规范:log.info(“programme_id:{}, appl_no:{}”, programmeId, applNo);

5)Controller 控制层严格接口参数校验,Service 业务逻辑层处理业务操作并减少与数据库交互次数(合理使用事务),Dao 层操作数据库;

6)sql 编写规范,where 条件要求走索引(索引优化、组合索引)等。

多交流、多讨论、多思考、多学习、多积累、多实践

1)持续学习、积累项目经验;

2)业余时间多研究框架源码;

3)积极参与需求讨论,合理设计解决方案。

4)积极思考业务场景,简化优化流程,提高用户体验;

5)多看别人的优秀代码并讨论,减少不必要的开发和踩先人以前的坑;

6)养成持续优化持续重构的意识。

加油

# 精彩推荐 #

 分布式系统「全链路日志追踪」实战之 RestTemplate & Feign

  小白都能看得懂的服务调用链路追踪设计与实现

  [三步法] 可视化分析定位线上 JVM 问题

  从 Java 代码如何运行聊到 JVM 和对象的创建-分配-定位-布局-垃圾回收

深入了解 Spring 中的事务(从核心注解和类入手)

 "在看"吗,赶快分享和收藏吧

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值