【项目实战典型案例】07.在线人员列表逻辑混乱反例
目录
一:背景介绍
该《案例07.在线人员列表逻辑混乱反例》中涉及到的问题:
1、类中写了公共变量导致数据混乱现象
2、保存数据没有考虑业务的隔夜覆盖导致的逻辑漏洞
3、 如果涉及到继承,对于this,父类有同样的成员你最终用的是那个呢?
4、 参数传递问题,参数不一致导致的后续维护混乱
5、 mysql由于关联字段类型不一致导致产生索引失效问题,进而产生慢sql
6、sql不考虑业务导致的明确逻辑漏洞
上面的问题主要分为四类问题:
1、公共变量(1)
2、业务逻辑问题( 2 4 6 )
3、面向对象的问题(3)
4、索引失效的问题(5)
二:思路&方案
公共变量导致数据混乱现象
由于线程共享全局变量,并在实际业务的过程中对全局变量进行了操作,所以在高并发、多线程的条件下会产生公共变量导致数据混乱的现象。
解决方案1 使用ThreadLocal
ThreadLocal介绍
ThreadLocal详解
1、ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。
2、ThreadLocal提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。
3、既然每个Thread有自己的实例副本,且其它Thread不可访问,那就不存在多线程间共享的问题。
4、ThreadLocal变量通常被private static修饰,当一个线程结束时,它所使用的所有ThreadLocal相对的实例副本都可被回收。
ThreadLocal常见使用场景
- 每个线程需要有自己单独的实例
- 实例需要在多个方法中共享,但不希望被多线程共享
ThreadLocal使用
多线程环境下未使用ThreadLocal出现数据混乱的问题
public class Client {
public static void main(String[] args) {
// 定义线程实现接口
Runnable runnable = new Runnable(){
Counter counter = new Counter();
@Override
public void run() {
counter.count();
}
};
// 启动10个线程
for( int i= 0;i< 10;i++) {
new Thread(runnable).start();
}
}
}
public class Counter{
private int number;
public void count(){
for (int i = 0; i <=10 ; i++) {
number=number+i;
}
System.out.println(Thread.currentThread().getName()+ "--"+number;
}
}
实现结果
正确计算结果都应该是55
多线程环境下使用ThreadLocal解决数据混乱的问题
public class Client {
public static void main(String[] args) {
// 定义线程实现接口
Runnable runnable = new Runnable(){
Counter counter = new Counter();
@Override
public void run() {
counter.count();
}
};
// 启动10个线程
for( int i= 0;i< 10;i++) {
new Thread(runnable).start();
}
}
}
public class Counter {
private static ThreadLocal<Integer> number = new ThreadLocal<Integer>() {
// 重写这个方法,可以修改“线程变量”的初始值,默认是null
@Override
protected Integer initialValue() {
return 0;
}
};
//计数方法
public void count() {
for( int i= 0;i<= 10;i++) {
number.set(number.get()+i);
}
System.out.println(Thread.currentThread().getName()+ "--"+number.get());
}
}
实现结果
解决方案2 将全局变量修改为成员变量
public void count(){
int number = 0;
for (int i = 0; i <=10 ; i++) {
number=number+i;
}
System.out.println(Thread.currentThread().getName()+ "--"+number);
}
}
实现效果
业务逻辑问题
在查询逻辑中添加了createDate的字段,如果13号这天学生没有下课的话,当14号这天你按照createDate字段查询的话,是查不到该学生的数据的,系统默认为该学生是第一次登录软件,所以就会再次存入一条该学生的数据。
上面的paramUser中已经有了isOnline参数,就不需要在进行赋值了,避免数据不一致。
1、如果更新了update_time,那么在线人员记录中的最近一次登录时间就修改为同一个了
2、如果在where条件上添加了create_date的话,那么过了12点结束课程后,所有在线的人就都无法下线了
面向对象继承问题
java中继承关系的父子类,相同的方法会被重写
当子类父类中的成员没有重名时,子类都可以通过this去调用。
当成员方法 重名,子类就会将父类中的方法进行重写。如果还想调用父类中的方法只能通过 super去进行调用。
当时成员变量不存在覆盖重写:在子类中只能通过super调用父类的
索引失效的问题
三:总结
做事情要从全局观出发,要明确事情的边界
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击