mysql jdbc allow_Jdbc Url 设置allowMultiQueries为true和false时底层处理机制研究

news/2025/1/13 3:34:09/

一个mysql jdbc待解之谜 关于jdbc  url参数 allowMultiQueries

如下的一个普通JDBC示例:

String user ="root";

String password = "root";

String url = "jdbc:mysql://localhost:3306";

Connection conn = java.sql.DriverManager.getConnection(url , user, password);

Statement stmt = conn.createStatement();

String sql = "select 'hello';select 'world'";

stmt.execute(sql);

执行时会报错:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select 'world'' at line 1

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

若一个sql中通过分号分割(或包含)了多个独立sql的话,如:

select 'hello';select 'world'

默认就会报上述错误,当若显式设置allowMultiQueries为true的话,就可以正常执行不会报错.如下所示:

String url = "jdbc:mysql://localhost:3306?allowMultiQueries=true";

allowMultiQueries

Allow the use of ';' to delimit multiple queries during one statement (true/false), defaults to 'false', and does not affect the addBatch() and executeBatch() methods, which instead rely on rewriteBatchStatements.

Default: false

Since version: 3.1.1

想要看看当该参数设置为true和false时,源码中到底哪里有不同.经过断点调试发现了在下面代码处会有不同的结果:

//所属类和方法:void java.net.SocketOutputStream.socketWrite(byte[] b, int off, int len) throws IOException

socketWrite0(fd, b, off, len);

bytesWritten = len;

当设置为true时,执行完socketWrite0方法后查询query log,会看到这样的输出:

23 Queryselect 'hello';

23 Queryselect 'world'

当设置为false时,执行完socketWrite0后.查询query log没有任何输出.

但奇怪的是它们的参数都一样,为什么一个有输出一个就没有呢?如下所示:

设置为true参数信息

7a4c95c5f1a72239aaa1b366c9251f9e.png

设置为false时的参数信息:

0f3a5f2417e675cdf91cfc51c289d1fe.png

补充: 即使当allowMultiQueries为false时,服务端也收到了查询请求,只不过没有在query log中输出而已.

如下抓包工具(Wireshark)所示:

8ada0069905be3005eeff1cc74ebd3a6.png

又经过进一步调试,发现如下几处代码可能比较关键,如下所示:

/**

*

* 所属: void com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(String user, String

* password, String database, Buffer challenge) throws SQLException

*/

// We allow the user to configure whether

// or not they want to support multiple queries

// (by default, this is disabled).

if (this.connection.getAllowMultiQueries()) { //1701行

this.clientParam |= CLIENT_MULTI_STATEMENTS;

}

last_sent = new Buffer(packLength);

last_sent.writeLong(this.clientParam); //1876行

执行完上述语句后,对应的query log为:

150507 21:23:16   19 Connectroot@localhost on

似乎是在这一交互过程中通知了服务器端客户端允许一次查询多条语句.通过抓包工具(wireshark)可以看到在创建连接过程中更多的交互信息,如下所示:

e0908910315c1a15823d3d5b0c57d205.png

但在调试过程中又遇到了一个新问题,若在上述代码处加上了断点,就会出现如下异常:

Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.

at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3161)

at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3615)

... 43 more

尚未找到该问题原因(如在何处设置的超时时间).但是实验发现,在创建连接过程中不能有debug调试(即不能有暂停),否则就会有fin包(不知这是Mysql的协议还是TCP的协议?).如下所示:

6aa25010d66e970e02a285128087b397.png

关于fin包的描述见wiki

895efff6dac79d63f4c254e9c7c6c2b7.png

但在成功建立连接后进行断点调试没有问题.

补充: 通过telnet来模拟上述现象.

# telnet 127.0.0.1 3306

Trying 127.0.0.1...

Connected to 127.0.0.1.

Escape character is '^]'.

J

5.6.17 <4/-7j1S- � 18fwG:-nh=66mysql_native_passwordConnection closed by foreign host.

对应的抓包信息:

a2064bf0c9d99869e2066f765bb93845.png

因未能及时输入密码,导致服务端发出FIN包中断了连接.

或者也可以通过如下Java代码来模拟此现象:

Socket socket = new  Socket("127.0.0.1",3306);

System.in.read();

此时看到的抓包信息如下所示:

4c5d0c30970705a543aeb45ca58c3f3d.png

补充:

1. 如何查看query log:

mysql>show variables like 'general_log%';

+------------------+--------------------------------------------------------------------+

| Variable_name    | Value                                                              |

+------------------+--------------------------------------------------------------------+

| general_log      | OFF                                                                 |

| general_log_file | /opt/mysql/server-5.6/data/zhuguowei-Presario-CQ43-Notebook-PC.log |

+------------------+--------------------------------------------------------------------+

mysql>set global general_log = 'on' ;

#开启另一终端

tail -f /opt/mysql/server-5.6/data/zhuguowei-Presario-CQ43-Notebook-PC.log

2. 关于使用抓包工具(Wireshark)

参考文档:

注意:

本地调试的话Interface(网卡)选择any(或lo), 过滤条件如下所示:

5b846f4bb330823d1bfabd1cf51522bc.png

其他问题:

1. 为什么在mysql交互终端中执行的命令不能被Wireshark捕捉到?

需要显式指定-h参数 如

mysql -u root -p -h 127.0.0.1

注意若为-h localhost的话,仍不能被Wireshark捕捉到,不知两者有什么区别?通过StackOverFlow中提问得到解答.

On Unix, MySQL programs treat the host name localhost specially, in a way that is likely different from what you expect compared to other network-based programs. For connections to localhost, MySQL programs attempt to connect to the local server by using a Unix socket file. This occurs even if a --port or -P option is given to specify a port number. To ensure that the client makes a TCP/IP connection to the local server, use --host or -h to specify a host name value of 127.0.0.1, or the IP address or name of the local server. You can also specify the connection protocol explicitly, even for localhost, by using the --protocol=TCP option.

摘自: https://dev.mysql.com/doc/refman/5.0/en/connecting.html

2. 在mysql交互终端中是否默认设置了allowMultiQueries=true, 能有办法将其改为false吗?

确实默认设置了allowMultiQueries=true, 如下所示:

257ff3b6aba7dbcdf09ce79c21645a2a.png

上图是通过Wireshark抓取终端mysql登录时(mysql -u root -p -h 127.0.0.1)抓取的包.

似乎没有修改的办法.

3. 如何在telent 127.0.0.1 3306后输入密码? 或者如何设置使得不用输入密码,试过使用--skip-grant-tables 启动mysql服务,但不起作用.


http://www.ppmy.cn/news/183371.html

相关文章

数据结构导论大题汇总

文章目录 前言&#xff1a;真题汇总搬家了&#xff01;&#xff01;&#xff01;一、应用题二、算法设计题 前言&#xff1a;真题汇总搬家了&#xff01;&#xff01;&#xff01; 自考本科数据结构导论&#xff08;02142&#xff09;历年&#xff08;应用题算法题&#xff09…

spring mvc学习(43):处理静态资源

上图是目录结构&#xff0c;本节是有问同学的&#xff0c;当好好总结 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.…

蓝桥杯 PREV-43 拉马车(试题解析)

试题 历届试题 拉马车 提交此题 评测记录 资源限制 时间限制&#xff1a;1.0s 内存限制&#xff1a;256.0MB 问题描述 小的时候&#xff0c;你玩过纸牌游戏吗&#xff1f;   有一种叫做“拉马车”的游戏&#xff0c;规则很简单&#xff0c;却很吸引小朋友。   其…

icom对讲机写频线定义_哈罗CQ火腿社区 - QRP and DIY - 各种写频线的资料,放上来备用吧 - Powered by phpwind...

原作者:广润通信(名古屋) 一、八重洲威泰克斯写频器: 1 手持机写频器(3.5MM 4段插头):支持可对八重洲/威泰克斯VX-1R 2R 5R 60R VX160/168/180/400/210A/418/428/等读写频(如写6R 7R需对接口作少许修改)。 注明:附带USB取电线防止因串口取电不足而没法读写频。 2 车载机…

业余无线电入门教程

文章目录 第 1 章 什么是业余无线电&#xff1f;1.1 解释两个名词1.2 五种常见的通联方式1.3 电台执照 第 2 章 Ham能够做什么&#xff1f;2.1 本地通联2.2 远程通联2.3 数字通联2.4 网上通联2.5 外空通联2.6 通联竞赛2.7 自制设备2.8 应急通讯 第 3 章 如何成为一名Ham3.1 中国…

笔记本不充电问题的解决

笔记本:HP CQ43 ,系统win7 ,电量不足100,总是显示 xx%可用(电源已接通,未充电),从网上找的解决办法好像也不起作用. 解决办法:将电源线连接笔记本一端接入笔记本电源接口时,稍稍保留一点,别完全插到底,就可以充电啦.HP CQ43可以确定这样解决,其他本子可以试试看.

ubuntu CQ45安装WIFI BCM4312

更新源 #sudo apt-get update 安装驱动 #sudo apt-get install bcmwl-kernel-source #Broadcom 802.11 Linux STA 无线驱动源 #sudo apt-get install broadcom-sta-common #sudo apt-get install broadcom-sta-source #sudo apt-get install b43-fwcutter …

CQ18阶梯赛第二场

H国的身份证号码I HihoCoder - 1558 只要单纯的判断一下前后的乘积就好了&#xff0c; 因为不是很想处理倍数的关系&#xff0c; 所以我这里是用 string去处理。 代码&#xff1a; 1 #include<bits/stdc.h>2 using namespace std;3 #define LL long long4 #define ULL u…