Jemter利用BeanShall连接远程数据库(SSH方式)
2022-08-06 08:07 第二个卿老师 阅读(654) 评论(0) 编辑 收藏 举报背景
准备
首先你得下载两个jar包,一个是mysql的,一个是java的搭建ssh代理的包
mysql包下载:官网(我使用的是mysql8,所以下载的是8.0.25)
java的ssh代理包下载:官网(我下载的是jsch-0.1.55.jar)
然后把包放在apache-jmeter-5.4.3\lib\ext目录下,再次重启jmeter即可(如果测试计划添底部引入jar包目录,可以不用重启jmeter)。
这时你应该还知道
- mysql的远程地址、端口号、数据库登录用户名及用户密码
- SSH服务器的远程地址、SSH端口号、服务器登录用户名及用户密码
接着
- 打开jmeter
- 添加一个jsr223取样器,选择beanshall
- 然后开始可以写代码调试了
我的完整代码如下,startSSH是开启SSH代理,testSSH是测试执行,可以把要执行的sql放这里面:
import java.sql.Connection; import java.sql.DriverManager; import java.net.DatagramSocket; import java.sql.ResultSet; import java.sql.Statement; import java.util.Date; import java.text.SimpleDateFormat; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; static int localPort = 3306;// 本地端口 static String remoteHost = "xxx";// 远程MySQL服务器 static int remotePort = 3306;// 远程MySQL服务端口 public static void startSSH() throws JSchException { // SSH连接用户名 String sshUser = "xxx"; // SSH连接密码 String sshPassword = "xxx"; // SSH服务器地址 String sshHost = "xxx"; // SSH服务器访问端口 int sshPort = 22; JSch jsch = new JSch(); Session session = jsch.getSession(sshUser, sshHost, sshPort); session.setPassword(sshPassword); // 设置第一次登录的时候提示,可选值:(ask | yes | no) session.setConfig("StrictHostKeyChecking", "no"); session.connect(); // 打印SSH服务器版本信息 System.out.println(session.getServerVersion()); try{ DatagramSocket ds=new DatagramSocket(3306); // 设置SSH本地端口转发,本地转发到远程 int assinged_port = session.setPortForwardingL(localPort, remoteHost, remotePort); // 设置SSH远程端口转发,远程转发到本地 // session.setPortForwardingR(remotePort, remoteHost, localPort); log.info("localhost:" + assinged_port + " -> " + remoteHost + ":" + remotePort); testSSH(); }catch (SocketException e){ System.out.println("busy port:"+i); } finally { // 删除本地端口的转发 session.delPortForwardingL(localPort); // 断开SSH链接 session.disconnect(); } // System.out.println("localhost:" + assinged_port + " -> " + remoteHost + ":" + remotePort); } public static void testSSH() throws Exception { Connection conn = null; Statement st = null; ResultSet rs = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // mysql8是这个,8以下用??? // 设置SSH本地端口转发后,访问本地ip+port就可以访问到远程的ip+port conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?useSSL=false&serverTimezone=GMT", "用户名", "用户密码"); st = conn.createStatement(); String userId = vars.get("userId"); String superior = vars.get("userName"); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = new Date(System.currentTimeMillis()); String time = formatter.format(date); String value = "('" + userName + "','" + userId + "'," + "1,'" + time +"')"; log.info("----" + value); // String value = "('111','111',1,'2022-07-26 17:32:32')";
// 定义sql String sql = "INSERT INTO t_user (userName,userId,status,time) VALUES " + value; // String sql2 = "SELECT * FROM t_invitation_relationship LIMIT 1;"; // rs = st.executeQuery(sql2); // select语句用 st.execute(sql); // insert语句用 // log.info("-------re:" + rs); // while (rs.next()) // System.out.println(rs.getString(1)); // } catch (Exception e) { throw e; } finally { // if (rs!=null) {rs.close();rs=null;} if (st!=null) {st.close();st=null;} if (conn!=null) {conn.close();conn=null;} } } startSSH();
最后
开始验证,运行jmeter,就可以看到已经连接成功了,如果有数据库报错,检查一下sql语句。
后记
我是在windows下运行的,当我尝试循环执行2次时,出现如下报错,报错提示为3306端口未注册。
而单次执行不会报错。。。
明明session连接已经关闭释放了,为什么会出现上述情况?查看端口情况,发现下图,期间执行了多次脚本。
原来每次 jmeter执行测试计划时会申请一个端口(如第二列的56751)去跟本地3306建立一个连接,虽然session连接释放只是关闭了tcp连接(对应图中的TIME_WAIT状态),未释放端口,所以第二次循环用同样的端口(56751)就绑定不了3306端口,就会报错。
而再次执行测试计划,会重新申请一个端口(如第二列的56735),这时就能绑定3306端口了,就不会报错。
那本地端口绑定的连接就不会关闭了吗?也不是:
- TIME_WAIT状态是TCP连接的一个状态,大概3分钟系统会自动清除连接
- 重启jmeter也会自动关闭连接
所以,只能把ssh代理脚本设置为循环期间仅一次执行或放入setUp线程组中,才能实现业务的循环操作。如果你有更优雅关闭端口绑定的办法,欢迎留言。