每日收获总结20250610
1.数据库除0解决
达梦数据库,sql中避免除0错误,先使用nullif(x,0)将除数0转化为null,然后使用COALESCE 将最后的计算结果转化为0。
COALESCE(SUM(TOUCH_TIMES) / NULLIF(COUNT(DISTINCT AD_ID), 0), 0)
oracle,mysql中都是类似的思路,先将为0的除数转为null,在将为null的计算结果转化为0。
nullif,和COALESCE是sql标准中的规定的函数。oracle,mysql,达梦数据库都适合。
2.不放过遇到的每一个问题,对于遇到的任何现象,多问为什么
一般什么样的人最厉害,经验丰富,遇到过很多问题,解决过很多问题。这不是挫折,和问题使人成功,而是挫折和困难使人思考,思考问题,思索答案,思考使人记忆深刻,思考使人成功。所以我们应该主动思考,而不是等到遇到困难再思考,像曾国潘那样,看书的时候,这句不读懂,不读下一句,多问自己为什么,多思考答案。以及做计划,复盘,为什么这些方式都被大多数成功学,成长教育的书提到,因为这些都需要思考。思考会在大脑里检索知识,经过深度思考,获得的答案,就相当于在大脑里给这个知识建立了索性。大脑是一个设计精妙的系统,思考问题,会在大脑里检索知识,并对知识建立索引,下次遇到问题,就能快速获得答案。
心理表征(我们对一个事物的任务,印象),就是我们已经建立了的索引。《思考,快与慢》中的,快速获得答案的就是我们已经在脑子中建立了索引或者缓存,形成了稳定的结构,以及通过神经突触进行链接。建立的索引或者缓存越多,在脑子中形成的稳定组织许多,我们的大脑整体运行速度就会提高很多。或许用索引来比喻不够形象,应该用缓存来做比喻会更加合适。因为思考问题得到的答案太久没使用,也容易遗忘,就像缓存过期了一般。
虽然好多问题的答案就在哪里,但是你看到了,却没思考为什么是它,下次遇到了这个问题还是无法解决。看到了未思考,就是混沌的,模糊的。只有自己在脑子里思考了,在脑子里检索了一遍,自己推理出了答案,它才会变得清晰,下次遇到了就能很快直接在脑子中找到答案。
所以,在编程中,我们需要将遇到的任何现象,知识点,技术点弄清晰,思考明白为什么,这样它们才能被清晰的留在我们的脑子里,从而避免看了就忘的问题。
3.依赖注入是什么,好处什么
许多类会依赖于一个或多个底层资源,如果我们在该类中直接new 一个依赖的底层资源类,那么它们就是强耦合的关系,如果依赖的资源类需要修改,则必须要修改该类的代码。所以在一个类依赖于其他类时优先考虑在创建实例时将该资源通过构造方法传入实例。这就是依赖注入。这种方式还有一种变种,就是将资源工厂传给构造器,这样创建实例时还可以通过资源工厂获取资源的子类资源进行注入。
在Spring中依赖注入这种思想得到了充分使用,不仅有构造器注入方式,还有set注入方式,和成员变量直接注入方式(@autoware)。通过构造器传参方式注入,这种方式要求资源非空,且资源不可变。set注入方式的作用是可选依赖,或者需要动态更新。另外如果有循环依赖问题,构造器注入方式无法自动处理,只有set注入方式能自动处理循环依赖。set方式注入的缺点是破坏封装性,难以校验完整的入参。
注入的对象来自于ioc容器,而ioc容器中的对象是根据配置文件来进行创建的。读取配置文件或者配置类,获取到类的全限定类名,通过反射创建出对象,注入到容器中,再注入到依赖它的类中。在spring中依赖的通常是接口,通过接口在容器去查找子类注入。如果依赖的接口需要修改实现方式,从一个实现切换为另一个实现,只需要修改配置文件即可。
具体方式是在通过@Configuration注解类下的@bean方式,将实现类注入到容器中时,添加一个条件注解,如果配置中是需要第一种实现,则@bean返回第一种方式bean的方法生效。如果配置的是第二种方式,就通过条件注解让返回第二种方法是@bean方法生效。这样就可以通过修改配置信息,使条件注解在不同的方法上生效,从而创建不同的实现对象放入容器中,达到注入不同的对象效果。而不需要修改任何代码,只需修改配置类。具体示例代码如下:
//1.定义支付接口与多个实现类
public interface PaymentService {void pay();
}@Component("alipay") // 标识为支付宝实现
public class AlipayService implements PaymentService {@Override public void pay() { System.out.println("支付宝支付"); }
}@Component("wechatPay") // 标识为微信支付实现
public class WechatPayService implements PaymentService {@Override public void pay() { System.out.println("微信支付"); }
}//2.在配置文件中指定当前激活的支付方式
# application.properties
payment.service=wechatPay # 可选值: alipay / wechatPay//3.通过配置类动态绑定接口实现
@Configuration
public class PaymentConfig {@Bean@ConditionalOnProperty(name = "payment.service", havingValue = "alipay")public PaymentService alipayService() {return new AlipayService();}@Bean@ConditionalOnProperty(name = "payment.service", havingValue = "wechatPay")public PaymentService wechatPayService() {return new WechatPayService();}
}//4.OrderService保持构造器注入不变
@Service
public class OrderService {private final PaymentService payment;// 依赖接口而非具体实现public OrderService(PaymentService payment) {this.payment = payment;}
}//如果需要切换支付方式
//只需修改配置文件
修改payment.service=alipay → 容器注入AlipayService实例
修改payment.service=wechatPay → 容器注入WechatPayService实例
4.redis分片集群原理
redis分片集群中,将整个数据集划分成16384(2kb.2*1024*8)多个槽,通过对key求hash,再求余的方式得到槽的位置,再根据槽的位置得到所在分片的ip。key和槽绑定,槽和ip绑定,这样在集群收缩时,key不需要再移动,只需将一批槽移动到新的机器ip就行。
在redis中pipeline操作中,pipeline本质上是批量操作,将同一批命令统一发送到一台机器上,要求是这批数据必须是同一个槽,如果不是会返回crossslot错误。可以通过{固定字母标签}+key的方式让这些key强制落入到同一个slot槽。也可将不同slot的命令分组执行pipeline操作。
5.输入法文字框跑到了左上角
输入法的bug,有些情况失去了鼠标焦点信息,比如切换了页面等,解决办法,鼠标点击一下屏幕上的输入法的log框,即可恢复。log框如下。
6.根据运维提供的慢sql以及进程名称查找服务
慢sql,在自己负责的服务中未找到,估计是其他服务连接了该数据库,执行的sql语句。通过PLSQL中的session找到了慢sql的进程名称,然后找到了client ip,最后进入该ip,查找到了该服务。
PLSQL中查看session方式:Tools->Sessions;可选All sessions,My sessions,Active sessions.