在认证成功后Cobar会将该连接的回调处理函数由FrontendAuthenticator(前端认证处理器)设置成FrontendCommandHanler(前端命令处理器)。
所以在客户端再次向Cobar发送请求报文的时候,前端命令处理器会处理该连接。下面详细分析一下简单select语句的执行过程。
1、事件的产生
NIOReactor的R线程一直在监听selector上的每个连接的感兴趣事件是否发生,当客户端发送了一条select * from tb1,select函数会返回,然后获取到该连接SelectionKey,并且该SelectKey的兴趣事件是OP_READ。此时会调用read(NIOConnection)函数。
| 02 |
final Selector selector = this.selector; |
| 06 |
int res = selector.select(); |
| 07 |
LOGGER.debug(reactCount + ">>NIOReactor接受连接数:" + res); |
| 09 |
Set keys = selector.selectedKeys(); |
| 11 |
for (SelectionKey key : keys) { |
| 12 |
Object att = key.attachment(); |
| 13 |
if (att != null && key.isValid()) { |
| 14 |
int readyOps = key.readyOps(); |
| 15 |
if ((readyOps & SelectionKey.OP_READ) != 0) { |
| 16 |
LOGGER.debug("select读事件"); |
| 17 |
read((NIOConnection) att); |
| 18 |
.............................. |
| 20 |
........................... |
2、调用该连接的read函数进行处理
该函数在上一篇中提到过,该函数的实现在AbstractConnection中,实现从channel中读取数据到缓冲区,然后从缓冲区完整的取出整包数据交给FrontendConnection类的handle()函数处理。
该函数交给processor进行异步处理。从processor中的线程池获取一个线程来执行该任务。这里调用具体的handler来进行处理。
刚开始提到的,当认证成功后,Cobar将连接的回调处理函数设置为FrontendCommandHandler。所以这里会调用前端命令处理器的handler函数进行数据的处理。
在这里需要先了解MySQL数据包的格式:

MySQL客户端命令请求报文
该处理函数如下:
| 01 |
public void handle(byte[] data) { |
| 02 |
LOGGER.info("data[4]:"+data[4]); |
| 04 |
case MySQLPacket.COM_INIT_DB: |
| 08 |
case MySQLPacket.COM_QUERY: |
| 12 |
case MySQLPacket.COM_PING: |
| 16 |
case MySQLPacket.COM_QUIT: |
| 20 |
case MySQLPacket.COM_PROCESS_KILL: |
| 24 |
case MySQLPacket.COM_STMT_PREPARE: |
| 25 |
commands.doStmtPrepare(); |
| 26 |
source.stmtPrepare(data); |
| 28 |
case MySQLPacket.COM_STMT_EXECUTE: |
| 29 |
commands.doStmtExecute(); |
| 30 |
source.stmtExecute(data); |
| 32 |
case MySQLPacket.COM_STMT_CLOSE: |
| 33 |
commands.doStmtClose(); |
| 34 |
source.stmtClose(data); |
| 36 |
case MySQLPacket.COM_HEARTBEAT: |
| 37 |
commands.doHeartbeat(); |
| 38 |
source.heartbeat(data); |
| 42 |
source.writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Unknown command"); |
由于每个报文都有消息头,消息头固定的是4个字节,前3个字节是消息长度,后面的一个字节是报文序号,如下所示

所以data[4]是第五个字节。也就是消息体的第一个字节。客户端向Cobar端发送的是命令报文,第一个字节是具体的命令。
如果是select语句,那么data[4]就是COM_QUERY,然后会调用具体连接的query成员函数,其定义在FrontendConnection类中。
| 01 |
public void query(byte[] data) { |
| 02 |
if (queryHandler != null) { |