【BUG共赏】static别乱用啊——并发场景下static变量导致的验证码发送失败

问题背景

最近在配合性能测试团队对项目接口进行性能测试。
今天收到测试小姐姐反馈:有一个请求验证码的接口,总有部分号码报错,经排查报错内容都是there has unsent record, can not send again! (此接口一天仅允许同一个号码请求一次)

问题排查

检查用例与工具

首先麻烦测试小姐姐排查了下测试用例与工具配置,排除测试用例号码重复或者工具对单个用例重复发送请求的可能

分析异常现象

现象1:(请求一次,记录多次)

  • 数据库出现单个号码多条记录 (即同一个号码有多个验证码请求记录)
  • 但是接口入口日志仅显示该接口处理了一次

现象2:(请求一次,没有记录,单独请求,可以成功)

  • 数据库中无某号码的记录
  • 但是接口入口日志显示该接口有请求
  • 再次单独执行该号码用例,可以成功
分析代码

快速走查了下代码,逻辑很简单 ,伪代码如下:

// 从请求中取出号码
accNbr = request.get("ACC_NBR");
// 检查是否发送过 (sql查询数据库)
if (isSend(accNbr)) {
    
    
	// 抛出异常
	throw exception;
}
send(accNbr);

从逻辑上看不出来问题原因,所以还是猜测是用例有相同号码导致的。

猜测 并发事务问题

很明显,这是并发才会有的问题
最开始,我还是怀疑用例有问题,代码没问题。感觉像是事务问题。
并且让测试写多个相同号码用例进行测试,复现这个问题。
在这里插入图片描述
果然复现了,所以我很自信的觉得问题找出来了。。。
在这里插入图片描述
嗯。。好像有点道理
但是性能测试还是坚称没有重复号码用例,重新检查了日志,的确没有。。

居然用static修饰了accNbr变量。。。

难道真的是代码有问题吗???
带着自我怀疑重新仔细检查代码。当我看到如下代码中号码变量定义时,我表示吐了呀!

// 变量定义
private static String accNbr;
// 处理请求
deal (request) {
    
    
	// 从请求中取出号码
	accNbr = request.get("ACC_NBR");
	// 检查是否发送过 (sql查询数据库)
	if (isSend(accNbr)) {
    
    
		// 抛出异常
		throw exception;
	}
	send(accNbr);
}
}

你没看错,居然用static修饰了这个变量。。这肯定线程不安全啊!!!
赶紧修改去掉static编译class发给测试小姐姐测试:
在这里插入图片描述

测试通过后的灵魂拷问

测试小姐姐表示好奇原因:
在这里插入图片描述
在这里插入图片描述
测试小姐姐表示学到了,但是灵魂拷问:咋想的??
在这里插入图片描述
我也想知道。。。看了下历史记录。。。原来是新来的小妹妹写的。。
我私聊问她为何要用static。。她表示不知道,是从别的地方拷贝过来的。。。
嗯。。能理解 并发给她一篇学习资料,认真学习一下static

总结

再对static做一个总结吧~避免犯这种低级错误!

java中全局变量与成员变量的区别

首先,java中其实没有全局变量的概念,只分为局部变量与成员变量

  • 局部变量:在方法内声明的变量,生命周期就是在该方法中;
● 局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
● 局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
  • 成员变量:在方法外声明的变量
● 成员变量定义在类中,在整个类中都可以被访问。
● 成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
局部变量
  • 但存在一个约定俗成的小区别:使用static声明的成员变量叫做全局变量
●  静态变量(也叫做类变量,类属性)
●  由static修饰的变量称为静态变量,其实质上就是一个全局变量。
●  如果某个内容是被所有对象所共享,那么该内容就应该用静态修饰;
没有被静态修饰的内容,其实是属于对象的特殊描述。

成员变量和静态变量的区别

  • 1.两个变量的生命周期不同
    • 普通成员变量只有在类创建对象后才开始存在,对象结束,它的生命也就告终。
    • 静态变量随着类的加载而存在,随着类的消失而消失。静态成员变量从类被加载开始到类被卸载,一直存在。
  • 2.调用方式不同
    • 成员变量只能被对象调用。
    • 静态变量可以被对象调用,还可以被类名调用。
  • 3.别名不同
    • 成员变量也称为实例变量。
  • -静态变量也称为类变量。
  • 4.数据存储位置不同
    • 成员变量存储在堆内存的对象中,所以也叫对象的特有数据,是每个对象单独使用的。
    • 静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据,是全类共享的。

都看到这里了 不妨点个赞吧!!!
如果有其他看法,欢迎在评论区交流!!!

猜你喜欢

转载自blog.csdn.net/qq_34577234/article/details/125240322
今日推荐