jmeter教程(十四):JDBC请求详解

在上一篇博文里面,我们实现了把数据库中的数据都查询了出来,但是查询出来,是为了使用的,那要怎么使用这些数据呢?在JDBC请求的配置页面,下面有五个输入框,和一个下拉框

前面两行是使用预编译sql的时候,输入参数的,这个下文中再讲。第三、四行,就是设置变量接收返回的结果的。第五行是设置执行sql的超时时间的。下拉框是选择处理sql执行后返回的结果的方式的,这个一般不用动。第三、四行都是设置变量来接收返回的结果的,第三行是设置几个变量,按列接收结果,第四行是设置一个变量,接收所有结果。一般使用第三行的设置。比如,我们在第三行输入:"id,name,image",注意,以英文的逗号分开不同的变量,这样就定义了三个变量,第一个变量是id,会接收结果中第一列的数据。id_0保存的就是数据的行数,id_1保存第一行的第一列数据,id_2保存第二行的第一列的数据,以此类推。为了验证一下,在线程组下添加一个ForEach控制器,ForEach控制器里添加java请求,打印每一行的id。

当然,End index for loop也可以使用变量:${id_0}

保存脚本,运行,看结果

这样就把所有商品的id都打印出来了。如果我只想要商品的名称,不要商品的其它属性,那么在JDBC请求配置页面,第三行,可以这样写:",name",因为name在第二列,所以name前面要加一个逗号。如果name在第三列,则要加两个逗号。

现在,我们来往数据库中插入一条数据。插入数据,是对数据库数据,做出更改,所以,Query Type要选择Updata Statement

然后运行

响应数据为1 updates,代表有一条数据更新了。然后在navicat里面刷新一下,再查看数据

数据插入进去了。

现在讲预编译,什么是预编译,为什么要用预编译?一条sql语句在数据库服务器上执行,是要经过很多步骤的,比如先要语法分析,然后要编译语句...如果一次要往一张表里插入很多条数据,而这些插入语句的格式都是一样的,那么,每次插入数据时都要做这些步骤,就必然有很大的一部分时间,数据库服务器都是在做着重复、无意义的步骤。所以,就出现了预编译功能,预编译,就是先把sql语句(不含数据),发往数据库服务器,数据库服务器会对这条SQL语句进行语法分析,并进行编译,但不会执行。等客户端把数据传过来,就直接执行,把数据插入到表中。这是使用预编译的一个好处,另一个好处就是可以防止sql注入。那么,怎么使用预编译功能呢?像往常写正常sql语句一样,只不过在有数据的地方,使用?代替,比如,原先插入数据的语句,使用预编译就可以写成:"INSERT INTO goods VALUES(null,?,?,?,?)",mysql服务器接收到这条sql语句,编译时,就知道,这条语句要接收四个参数,把四个参数传给它,它就会直接执行了,不会再进行语法分析、编译的步骤了。下面,就在jmeter体验一把

Query Type要选Prepared Update Statement,下面的输入框,第一行是要插入的数据,字符串不要加引号,第二行是数据的类型,与上面的数据一一对应,这个类型有点坑,看我填的就知道了。。。我也是试了好多次才试出来的。保存脚本,运行,看结果

然后,用预编译的形式,执行查询语句

Query Type选Prepared Select Statement,保存脚本,运行,看结果

下面,我们来写一个模拟抢购商品的流程案例,新建一个脚本,添加三个线程组,第一个线程组,设置id为1的商品库存为200,第二个线程组中,减少商品的库存4,相当于是顾客购买了4个商品。第三个线程组中,查看最终的库存。

现在,有3个线程组,如果执行的话,三个线程是同时执行的,所以先执行哪一个是不确定的,为了确保3个线程组按顺序执行,需要在测试计划中设置一下,独立运行每个线程组

然后执行一下,看结果

现在,把线程组2的线程数设置为10,相当于有10个人在购买商品了。然后循环次数设置为6,也就是每个人都会购买6次,每次购买4个商品。

然后,再运行

这个时候,就看到库存出现了负数,这是有问题的。那么,这个时候,通常会在减少4个库存之前,先查询一下商品的库存,如果商品的库存大于等于4,才减少4个库存,于是

再次运行脚本

到后面,查询库存为0时,就不会再减库存了。问题似乎解决了,但还是有问题的,如果运气够好,还是会出现负库存的,为什么呢?因为在线程组有两步操作,先查询再减库存,如果剩4个库存的时候,有一个线程来查询一下库存,有4个,但它还没来得及减库存,另一个线程先查询了一下库存,也有4个,然后两个线程,都执行一下减库存的操作,就又出现负的库存了,这就是线程安全问题。为了模拟出现这种情况,我们改写一下脚本,把线程组1和线程组3,去掉,然后把线程组2复制一份,再把测试计划中的独立运行线程组的勾去掉,然后两个线程组2的循环次数都改为3,即原来的一半

不过,现在脚本中没有设置库存的步骤,需要用navicat改

可以直接在表格中改,改好后,点下面的勾就可以生效,或是按Ctrl+s,也可以生效。然后,运行脚本

我们脚本的执行逻辑,是先查询,再减库存,但看结果中执行的顺序,有些与脚本中的步骤是不一样的,这就是不同的线程执行出现的结果。当然,最后的库存出现了负数,并不是每次都会出现的。可能需要多运行几次,才会出现。现在,我就要多线程执行,但又要保证不会出现负库存的问题,怎么办?方法就是加锁,在前面讲逻辑控制器,还有一个没讲,那个就是用来加锁的。什么是锁,为什么要用锁?锁可以简单地看做是一种权限,有了锁,你就能做一些操作,没有锁,你就不行。锁就是为了解决线程安全问题的。通过给一段代码加锁,那么有锁的线程可以执行这段代码,没有锁的,就不能执行,需要等,等到别人释放了锁,它去获得锁,获得了锁之后才能够执行这段加了锁的代码(编程中叫同步代码块)

两个线程组里面,都添加逻辑控制器Critical Section Controller,然后把原先的查询库存和减库存的操作都放到这个控制器里面。再次运行脚本,当然要先设置库存

这样,就不会出现负库存了。查看上面代码的执行顺序,也可以看到都是一个查询库存一个减库存,没有出现顺序错乱的情况了。其实呢,这个案例最好的简单办法,是使用一条sql语句搞定:UPDATE goods SET stock=stock-4 WHERE id=1 AND stock>=4,仅适用于单例的数据库服务器,如果是分布式的,这样就不行了。每一条sql语句执行,在数据库服务器里也是会加锁的。至于数据库服务器加锁的机制,又可以讲一大篇了,这里略。

欢迎加入测试群:91425817,一起讨论测试的那此事。

发布了47 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/kingzhsh/article/details/86562816