三、MyCat 客户端 SQL 请求执行流程

在这里插入图片描述

  • RW#run 轮询注册队列中是否有 AbstractConnection,若存在且为读事件则调用 AbstractConnection#asynRead 异步读取数据,实际处理逻辑见 NIOSocketWR#asynRead

  • NIOSocketWR#asynRead 从 前端连接的 channel 中读取数据,并且保存到对应 AbstractConnectionreadBuffer 中,之后调用 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()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值