-
RW#run
轮询注册队列中是否有AbstractConnection
,若存在且为读事件则调用AbstractConnection#asynRead
异步读取数据,实际处理逻辑见NIOSocketWR#asynRead
-
NIOSocketWR#asynRead
从 前端连接的channel
中读取数据,并且保存到对应AbstractConnection
的readBuffer
中,之后调用AbstractConnection#onReadData
处理读取到的数据@Override public void asynRead() throws IOException { ByteBuffer theBuffer = con.readBuffer; if (theBuffer == null) { theBuffer = con.processor.getBufferPool().allocate(con.processor.getBufferPool().getChunkSize()); con.readBuffer = theBuffer; } // 从 SocketChannel 中读取数据,并且保存到 AbstractConnection 的 readBuffer 中,readBuffer 处于 write mode,返回读取了多少字节 int got = channel.read(theBuffer); // 调用处理读取到的数据的方法 con.onReadData(got); }
-
AbstractConnection#onReadData
读取readBuffer
中的数据并调用AbstractConnection#handle
方法进行下一步处理,其内部调用FrontendCommandHandler#handle
-
FrontendCommandHandler#handle
根据data[4]
来判断命令类型,客户端命令请求报文格式如下图:
data 的第五个字节存储命令类型,客户端命令请求报文命令类型详情表见附录1。我们以 MySQLPacket.COM_QUERY
为例进行接下来的讨论。当 data[4] == MySQLPacket.COM_QUERY
时,调用 FrontendConnection#query(byte[])
public void handle(byte[] data) {
// 判断命令类型
switch (data[4]) {
...
// INSERT/SELECT/UPDATE/DELETE 等 SQL 归属于 MySQLPacket.COM_QUERY
case MySQLPacket.COM_QUERY:
commands.doQuery();
source.query(data);
break;
...
}
}
-
FrontendConnection#query(byte[])
将data
字节数组转化成String
类型的 SQL,ServerQueryHandler#query(String)
方法public void query(byte[] data) { MySQLMessage mm = new MySQLMessage(data); // 从 data[5] 即第六个字节开始读取参数体 mm.position(5); String sql = mm.readString(charset); // 执行 sql 语句,内部调用 ServerQueryHandler#query(String) this.query( sql ); }
-
ServerQueryHandler#query(String)
解析 SQL 类型,根据sqlType
使用不同的Handler
做处理@Override public void query(String sql) { ServerConnection c = this.source; /* 解析 SQL 类型 */ int rs = ServerParse.parse(sql); int sqlType = rs & 0xff; switch (sqlType) { // explain2 datanode=? sql=? case ServerParse.EXPLAIN2: Explain2Handler.handle(sql, c, rs >>> 8); break; case ServerParse.SELECT: SelectHandler.handle(sql, c, rs >>> 8); break; case ... default: if (readOnly) { LOGGER.warn(new StringBuilder().append("User readonly:").append(sql).toString()