## 则一后端开发注意事项 ### 数据库 目前数据库1个主库,2个读库,应用服务使用写库以及读库1,报表服务使用读库2 #### 创建表 必须字段 主键: id varchar(36) 删除标识: delete_flag tinyint(1) 创建时间:create_time datetime 创建人:create_user varchar(255) 创建人 修改时间:modify_time datetime 修改时间 修改人: modify_user varchar(255)修改人 一般还需要业务主键、状态、备注等等字段 #### 索引 创建表必须加一个主键索引id 一般需要加一个业务主键,索引类型为唯一索引,保证数据不能重复添加(例如派车单号,运单号,账单号) where后面查询字段要设置索引 SQL写完一定要在生产环境执行一下,看下执行计划有没有走索引,执行时间一般控制在1-2秒以内 大量数据的查询要控制时间范围,例如运单,派车单一次最多查询3个月的数据据 事务内的查询会走主库 #### 常见生产问题⭐⭐⭐⭐⭐ - 慢SQL导致大量会话阻塞,系统查询慢或者无法查询 - 关联查询或主子查询创建了大数据量临时表,导致数据库临时表空间暴增,数据库无法读写 - 事务中的查询SQL直接走主库,SQL的where条件没加索引,大数据量查询导致了主库的CPU飙高 - 数据更新事务长时间未提交,导致其他事务无法操作,造成数据库死锁 例如开启事务之后http请求超时未响应 ### 后台接口 #### 接口设计 ##### 命名规范⭐⭐⭐⭐ 类名一般为名词或名词组合,需要使用大驼峰命名法(UpperCamelCase) 风格 方法名、参数名、成员变量、局部变量需要使用小驼峰命名法(lowerCamelCase) 常量、枚举名称需要使用蛇形命名法(snake_case),常量以及枚举名称需要全部大写 例如:OUT_INVITE 包名统一使用小写,尽量使用单个单词作为包名,各个单词通过"."分隔符连接,并且各个单词必须为单数 POJO类中布尔类型的变量,都不要加is前缀,否则部分框架解析会引起序列化错误 如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式 抽象类命名使用Abstract开头 异常类命名使用Exception结尾 测试类命名以它要测试的类的名称开始,以Test结尾 ##### 接口定义⭐⭐⭐⭐ 单一职责原则(Single Responsibility Principle) 开闭原则(Open Closed Principle) 里氏替换原则(Liskov Substitution Principle) 迪米特法则(Law of Demeter)又叫"最少知道法则" 接口隔离原则(Interface Segregation Principle) 依赖倒置原则(Dependence Inversion Principle) ##### 方法定义⭐⭐⭐⭐ 方法名的第一个单词应该是动词,首字母应小写。参数的名字必须和变量的命名规范一致。使用有意义的参数命名。参数尽量简化,不要定义方法中用不到的参数。超过5个则定义成对象类型 注意:方法职责一定要拎清楚,代码乱最根本的原因就是接口或者方法的定义的有问题,职责没有拎清楚 ##### 注释⭐⭐⭐ 接口方法注释一定要写清楚 #### 缓存⭐⭐⭐ 基础数据最好加缓存,减小数据库压力,提高查询效率 #### 事务⭐⭐⭐⭐ 增删改方法一定要加事务注解 嵌套事务注意用try catch包住内部事务方法的异常 定时任务需要注意如果其中一条数据异常是否需要全部回滚 ###### 常见问题⭐⭐⭐⭐⭐ 未加事务注解导致数据不一致 ```java @Override @Transactional public String createDispatch(CreateDispatchRequestDto createDispatchRequestDto) { waybillService.createWaybill(dispatchCode, waybillCode); dispatchStopOverStationService.createDispatchStation(createDispatchStationRequestDto); dispatchVehicleService.createDispatchVehicle(createDispatchRequestDto); dispatchPriceService.createDispatchPrice(createDispatchRequestDto); dispatchSupplierPriceService.createDispatchSupplierPrice(createDispatchRequestDto); try { //带事务方法 dispatchOperationRecordService.createDispatchOperationRecord(createDispatchRequestDto); } catch (Exception e) { log.error("创建派车单异常!"); } } ``` ##### 异常 检查性异常处理一定要打日志 ###### 常见问题⭐⭐⭐⭐⭐ 直接catch掉异常,异常信息无法定位 ```java try { //业务逻辑 } catch (Exception e) { log.error("钉钉审批回调消费异常!"); throw new BusinessException("钉钉审批回调消费异常!"); } ``` 正确示例 ```java try { //业务逻辑 } catch (Exception e) { log.error("钉钉审批回调消费异常!", e); throw new BusinessException("钉钉审批回调消费异常!", e); } ``` #### 定时任务 要注意定时任务事务回滚问题。理清楚当有异常产生时,是要全部回滚还是正常执行完。 常见问题⭐⭐⭐⭐ 定时任务异常未处理,导致整个事务回滚,任务执行失败! #### 版本兼容 APP后台开发要注意版本兼容问题,APP前端版本上线后不一定所有用户都能及时更新版本。要保证老版本使用的接口也能做出准确的响应 外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方造成影响。接口过时加@Deprecated注解,并清晰地说明新接口或新服务是什么 ###### 常见问题⭐⭐⭐⭐⭐ APP未做版本兼容,导致老版本APP无法正常使用 直接改外部正在调用的接口,导致别的服务不可用 废弃的接口直接抛业务异常 ```java @PostMapping("/add") public Response addDriverVehicleLicense(@RequestBody @Validated DriverVehicleLicenseAddRequestDto driverVehicleLicenseAddRequestDto) { throw new BusinessException("请下载最新APP版本!"); } ``` 新老版本并行的接口加版本区分 ```java /** * 新增 */ @PostMapping("/add") public Response addDriverVehicleLicense(@RequestBody @Validated DriverVehicleLicenseDiscernAddRequestDto driverVehicleLicenseAddRequestDto) { driverVehicleLicenseService.addDriverVehicleLicense(driverVehicleLicenseAddRequestDto); return returnSuccess(); } /** * 新增(接口兼容:增加行驶证背面传递到副页字段) */ @PostMapping("/add/v1") public Response addDriverVehicleLicenseV1(@RequestBody @Validated DriverVehicleLicenseDiscernAddRequestDto driverVehicleLicenseAddRequestDto) { driverVehicleLicenseService.addDriverVehicleLicenseV1(driverVehicleLicenseAddRequestDto); return returnSuccess(); } ``` #### git 分支:开发分支,测试分支,上线分支,master 开发分支: 开发功能时要创建自己的开发分支,开发分支从master创建分支,一般一个需求对应一个分支 测试分支: 测试环境部署的分支,功能开发完通过单元测试后就可以把代码合并到测试分支进行测试 上线分支: 每周会有一个上线版本,上线之前需要把要上线的代码合并到上线分支,从自己的开发分支合并到上线分支 master: 生产环境部署分支,由上线部署人员从上线分支合并到master __push之前一定拉下代码,push时一定要看下是不是自己的代码,一定要看全部内容,注意提交内容多时会有省略号,要一直点到最后没有省略号为止。如果把不上线的代码push到上线分支,所有人都得重新合代码了,直接影响上线。一定要注意!!!!!__ ##### 常见问题⭐⭐⭐⭐⭐ push时把别人不上线的代码push到上线分支