Java 业务开发常见错误 100 例 -- 学习笔记 -- 3

21 | 代码重复:搞定代码重复的三个绝招

为什么要解决代码重复问题?
当重复代码中出现bug时,如果重复次数过多或对代码结构不了解,很有可能会出现改bug改了一半的情况,所以消除重复代码可以从一定程度上提高代码的可维护性
利用工厂模式 + 模板方法模式,消除 if…else 和重复代码
使用抽象类,对统一方法进行实现而遗留不相同的方法给子类实现(模板方法模式),再在使用时选择对应的bean进行注入即可使用spring完成工厂模式,从而降低代码重复度。
利用注解 + 反射消除重复代码
“许多涉及类结构性的通用处理,都可以按照这个模式来减少重复代码”
感觉不如写个工具类。。。
利用属性拷贝工具消除重复代码
使用Bean映射工具
比如在DO和DTO中有大量属性需要赋值时,就可以使用这种方法,之前还真写过DTO和DO对象之间十几行属性的赋值,早知道就好了捏。

BeanUtils.copyProperties(orderDTO, orderDO, "id");

22 | 接口设计:系统间对话的语言,一定要统一

接口的响应要明确表示接口的处理结果
接口设计的两个原则:

  1. 对外隐藏内部实现
  2. 设计接口结构时,明确每个字段的含义,以及客户端的处理方式。
    明确接口的设计逻辑(例):
@Data
public class APIResponse<T> {
    private boolean success;
    private T data;
    private int code;
    private String message;
}

请添加图片描述
在开发接口之前明确版本控制策略,以及尽量使用统一的版本控制策略两方面
明确接口的同步异步

23 | 缓存设计:缓存可以锦上添花也可以落井下石

不要把 Redis 当作数据库
原因:

  1. 当Redis 中数据消失导致业务逻辑错误时,若没有保留原始数据,业务都无法恢复。
  2. Redis缓存的大小无法超过内存大小

因此,把 Redis 用作缓存,我们需要注意两点:
3. 从客户端的角度来说,缓存数据的特点一定是有原始数据来源,且允许丢失
4. 从 Redis 服务端的角度来说,缓存系统可以保存的数据量一定是小于原始数据的。

注意缓存雪崩问题
从广义上说,产生缓存雪崩的原因有两种:
第一种是,缓存系统本身不可用,导致大量请求直接回源到数据库;
第二种是,应用设计层面大量的 Key 在同一时间过期,导致大量的数据回源。
第一种属于系统配置问题,这里我们只解决第二种。
解决方案一:差异化缓存过期时间
解决方案二:让缓存不主动过期

注意缓存击穿问题
解决方案一:双重检查的分布式锁,但是该方法过于严格,会降低系统的并发效率
解决方案二:使用进程内的锁进行限制,这样每一个节点都可以以一个并发回源数据库
解决方案三:使用工具限制会员并发数

注意缓存穿透问题
解决方案一:对于不存在的数据,同样设置一个特殊的 Value 到缓存中
解决方案二:布隆过滤器

注意缓存数据同步策略
先更新数据库再删除缓存,访问的时候按需加载数据到缓存,并且要尽量设置合适的缓存过期时间,这样即便真的发生不一致,也可以在缓存过期后数据得到及时同步。

24 | 业务代码写完,就意味着生产就绪了?

蒸的。。。看不懂。。。

25 | 异步处理好用,但非常容易用错

异步处理常常配合MQ中间件使用

  1. 要考虑异步流程丢消息或处理中断的情况,需要有备线进行补偿。
  2. 异步处理的时候需要考虑消息重复的可能性,处理逻辑需要实现幂等,防止重复处理。
  3. 微服务场景下不同服务多个实例监听消息的情况,一般不同服务需要同时收到相同的消息,而相同服务的多个实例只需要轮询接收消息。我们需要确认 MQ 的消息路由配置是否满足需求,以避免消息重复或漏发问题。
  4. 要注意始终无法处理的死信消息,可能会引发堵塞 MQ 的问题。

26 | 数据存储:NoSQL与RDBMS如何取长补短、相辅相成?

数据库的选用主打一个相辅相成,没有哪一种数据库是全能的
Redis 对单条数据的读取性能远远高于 MySQL,但不适合进行范围搜索。
InfluxDB 对于时间序列数据的聚合效率远远高于 MySQL,但因为没有主键,所以不是一个通用数据库。
ES 对关键字的全文搜索能力远远高于 MySQL,但是字段的更新效率较低,不适合保存频繁更新的数据。
最后,我们给出了一个混合使用 MySQL + Redis + InfluxDB + ES 的架构方案,充分发挥了各种数据库的特长,相互配合构成了一个可以应对各种复杂查询,以及高并发读写的存储架构。
请添加图片描述

27 | 数据源头:任何客户端的东西都不可信任

  1. 客户端的计算不可信,例如:购物车计算应付款,仅能供参考
  2. 所有来自客户端的参数都需要校验判断合法性,防止有人通过接口工具等方式越过前端直接提交从而造成数据异常
  3. 除了请求 Body 中的信息,请求头里的任何信息同样不能信任。IP、cookie等数据仅供参考,不能运用到重要的业务逻辑中,可以使用第三方登录等方式来做唯一标识
  4. 如果接口面向外部用户,那么一定不能出现用户标识这样的参数,当前用户的标识一定来自服务端,只有经过身份认证后的用户才会在服务端留下标识。

28 | 安全兜底:涉及钱时,必须考虑防刷、限量和防重

开放平台资源的使用需要考虑防刷,比如发送短信或者网站流量等方面,解决方案有正常使用流程识别、人机识别、单人限量和全局限量等
虚拟资产并不能凭空产生无限使用,例如在发放优惠券之前一定要设置优惠券总数,防止变现造成大额损失
钱的进出一定要和订单挂钩并且实现幂等
任何资金操作都需要在平台侧生成业务属性的订单,一定是先有订单再去做资金操作。
一定要做好防重,也就是实现幂等处理,并且幂等处理必须是全链路的。这里的全链路是指,从前到后都需要有相同的业务订单号来贯穿,实现最终的支付防重。

29 | 数据和代码:数据就是数据,代码就是代码

对于 SQL 注入来说,避免参数化的查询是最好的堵漏方式;对于 MyBatis 来说,我们需要使用“#{}”进行参数化处理。
对于 XSS 攻击,处理安全问题需要确保三点。(以下原文)
第一,要从根本上、从最底层进行堵漏,尽量不要在高层框架层面做,否则堵漏可能不彻底。
第二,堵漏要同时考虑进和出,不仅要确保数据存入数据库的时候进行了转义或过滤,还要在取出数据呈现的时候再次转义,确保万无一失。
第三,除了直接堵漏外,我们还可以通过一些额外的手段限制漏洞的威力。比如,为 Cookie 设置 HttpOnly 属性,来防止数据被脚本读取;又比如,尽可能限制字段的最大保存长度,即使出现漏洞,也会因为长度问题限制黑客构造复杂攻击脚本的能力。

30 | 如何正确保存和传输敏感数据?

用户密码不能简单的加密(如md5)保存,更不能明文保存,需要使用全球唯一的、具有一定长度的、随机的盐(例如UUID),配合单向散列算法保存
姓名和身份证这种需要可逆解密查询的敏感信息,需要使用对称加密算法保存。本书作者的建议是,把脱敏数据和密文保存在业务数据库,独立使用加密服务来做数据加解密;对称加密需要用到的密钥和初始化向量,可以和业务数据库分开保存
数据传输则务必通过 SSL/TLS 加密进行传输

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值