Jdbc Url 设置allowMultiQueries为true和false时底层处理机制研究
一个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 Query select 'hello';
23 Query select 'world'
当设置为false时,执行完socketWrite0后.查询query log没有任何输出.
但奇怪的是它们的参数都一样,为什么一个有输出一个就没有呢?如下所示:
设置为true参数信息

设置为false时的参数信息:

补充: 即使当allowMultiQueries为false时,服务端也收到了查询请求,只不过没有在query log中输出而已.
如下抓包工具(Wireshark)所示:

又经过进一步调试,发现如下几处代码可能比较关键,如下所示:
/**
*
* 所属: 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 Connect root@localhost on
似乎是在这一交互过程中通知了服务器端客户端允许一次查询多条语句.通过抓包工具(wireshark)可以看到在创建连接过程中更多的交互信息,如下所示:

但在调试过程中又遇到了一个新问题,若在上述代码处加上了断点,就会出现如下异常:
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的协议?).如下所示:

关于fin包的描述见wiki

但在成功建立连接后进行断点调试没有问题.
补充: 通过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.
对应的抓包信息:

因未能及时输入密码,导致服务端发出FIN包中断了连接.
或者也可以通过如下Java代码来模拟此现象:
Socket socket = new Socket("127.0.0.1",3306);
System.in.read();
此时看到的抓包信息如下所示:

补充:
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)
参考文档:
http://www.maketecheasier.com/using-wireshark-ubuntu/
http://floss.zoomquiet.io/data/20120511105248/index.html
注意:
本地调试的话Interface(网卡)选择any(或lo), 过滤条件如下所示:

其他问题:
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, 如下所示:

上图是通过Wireshark抓取终端mysql登录时(mysql -u root -p -h 127.0.0.1)抓取的包.
似乎没有修改的办法.
3. 如何在telent 127.0.0.1 3306后输入密码? 或者如何设置使得不用输入密码,试过使用--skip-grant-tables 启动mysql服务,但不起作用.
Jdbc Url 设置allowMultiQueries为true和false时底层处理机制研究的更多相关文章
- JDBC的URL设置allowMultiQueries的原因
如下的一个普通JDBC示例: String user ="root";String password = "root";String url = "j ...
- easyui-combobox的option选项为true与false时的问题
如题,我们使用easyui-combobox,当我们的选择项为true与false时,即选择是否,后台返回一个boolean类型的变量,那么这时候,通过form表单进行反显会出现这样的问题:表单里ea ...
- mysql的jdbc.url携带allowMultiQueries=true参数的作用及其原理
如下配置 jdbc.url=jdbc:mysql://127.0.0.1:3306/chubb_2?autoReconnect=true&useUnicode=true&charact ...
- motto - question - bodyParser.urlencoded 中设置 extended 为 true 和 false 有什么区别吗?
本文搜索关键字:motto node nodejs js javascript body-parser bodyparser urlencoded x-www-form-urlencoded exte ...
- C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思?
原文:C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思? 在 .NET 中创建进程时,可以传入 ProcessStartInfo ...
- Mysql JDBC Url参数说明useUnicode=true&characterEncoding=UTF-8
MySQL的 JDBC URL 格式 for Connector/J 如下例: jdbc:mysql://[host][,failoverhost...][:port]/[database] » [ ...
- [android] setOnTouchEvent 设置返回值为true 和 false的区别
今天在做自定义的可选文本的 TextView 类时,用到了 View 类的 setOnTouchListener(OnTouchListener l)事件监听,在构造 OnTouchListener ...
- MySQL JDBC URL参数(转)
MySQL的 JDBC URL格式: jdbc:mysql://[host][,failoverhost...][:port]/[database] » [?propertyName1][=prope ...
- com.mysql.cj.jdbc.Driver 新特性jdbc.url连接供参考
com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6及以上版本中的参数详解: jdbc.url=jdbc:mysql://localhost:3306/t ...
随机推荐
- 回文(palindrome)
如果一个字符串忽略标点符号.大小写和空格,正着读和反着读一模一样,那么这个字符串就是palindrome(回文).
- Tarjan缩点求入度为零的点的个数问题
Description: 一堆人需要联系,但如果x 可以联系 y,你联系了x就不用联系y了,你联系一个人都会有固定的花费,问你最小联系多少人,和最小花费 Solution: Tarjan缩点,求出缩点 ...
- Android记录10--android.os.NetworkOnMainThreadException异常解决办法
2013年11月1日小光棍节 有一段时间没有发表新的博客了,最近一直在忙着开发新浪微博客户端遇到很多问题比较头痛,比如说本篇博客要讲的NetworkOnMainThreadException这个异常, ...
- day01_雷神_Python入门
day01 1.编程语言 主流的像C.java.python.php.C#.等,可以从不同维度分类如下: 机器码和字节码 机器码: C 字节码: 其他 note: 机器码是电脑的CPU可直接解读的数据 ...
- vmtools是灰色不可用的
- fping常用参数介绍
fping的主要参数有以下两个: -a:只显示存活主机: -u:只显示不存活主机: -l:循环ping目标IP地址的输入方式: fping IP1 IP2 IP3 ...: fping -f file ...
- 简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析
简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析 虽然经常用 OAuth 2.0,但是原理却不曾了解,印象里觉得很简单,请求跳来跳去,今天看完相关介绍,就来捋一捋 ...
- 剑指offer编程题Java实现——面试题7用两个栈实现队列
题目:用两个栈实现一个队列.队列的声明如下:请实现他的两个函数appendTail和deleteHead, 分别完成在队列尾部插入节点和在队列头部删除节点的功能. package Solution; ...
- 面向对象总结、configparser配置文件模块、logging日志模块
面向对象总结 # 学习态度# python基础 2个月# html css js jq 1个月 # 上课困 # 学习方法 :# 列出知识点# 例子 写了哪些 # 面向对象学了哪些块# 为什么要讲面向对 ...
- 转---单页面应用下的JS内存管理
正文从这开始- 内存问题对于后端童鞋而言可能是家常便饭,特别是C++童鞋.我在实习时做过半年的c++游戏客户端开发(也是前端开发哦),也见识了各式各样的内存问题,就说说我的第一个坑,当时做个需求,就是 ...