大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 Mycat原理解析:SQL語句的處理

Mycat原理解析:SQL語句的處理

更新時間:2021-09-17 10:57:32 來源:動力節點 瀏覽2483次

Mycat原理的內容有很多,這篇主要來說說Mycat對SQL語句的處理。

Mycat接收到客戶端的sql語句時,會統一使用ServerQueryHandler.query(String sql)方法來處理,ServerQueryHandler主要做了兩件事情。

1,.確定sql的類型。比如:SELECT、UPDATE、INSERT、SHOW等

2.將不同類型的sql交給不同的處理器進行處理

@Override
public void query(String sql) {
    ServerConnection c = this.source;
    //確定sql類型
    int rs = ServerParse.parse(sql);
    int sqlType = rs & 0xff;

    //將不同類型的sql交給不同的處理器進行處理
    switch (sqlType) {
    //explain sql
    case ServerParse.EXPLAIN:
        ExplainHandler.handle(sql, c, rs >>> 8);
        break;
    //explain2 datanode=? sql=?
    case ServerParse.EXPLAIN2:
        Explain2Handler.handle(sql, c, rs >>> 8);
        break;
    case ServerParse.SET:
        SetHandler.handle(sql, c, rs >>> 8);
        break;
    case ServerParse.SHOW:
        ShowHandler.handle(sql, c, rs >>> 8);
        break;
    case ServerParse.SELECT:
        SelectHandler.handle(sql, c, rs >>> 8);
        break;
    case ServerParse.START:
        StartHandler.handle(sql, c, rs >>> 8);
        break;
    case ServerParse.BEGIN:
        BeginHandler.handle(sql, c);
        break;
    //不支持oracle的savepoint事務回退點
    case ServerParse.SAVEPOINT:
        SavepointHandler.handle(sql, c);
        break;
    case ServerParse.KILL:
        KillHandler.handle(sql, rs >>> 8, c);
        break;
    //不支持KILL_Query
    case ServerParse.KILL_QUERY:
        LOGGER.warn(new StringBuilder().append("Unsupported command:").append(sql).toString());
        c.writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR,"Unsupported command");
        break;
    case ServerParse.USE:
        UseHandler.handle(sql, c, rs >>> 8);
        break;
    case ServerParse.COMMIT:
        c.commit();
        break;
    case ServerParse.ROLLBACK:
        c.rollback();
        break;
    case ServerParse.HELP:
        LOGGER.warn(new StringBuilder().append("Unsupported command:").append(sql).toString());
        c.writeErrMessage(ErrorCode.ER_SYNTAX_ERROR, "Unsupported command");
        break;
    case ServerParse.MYSQL_CMD_COMMENT:
        c.write(c.writeToBuffer(OkPacket.OK, c.allocate()));
        break;
    case ServerParse.MYSQL_COMMENT:
        c.write(c.writeToBuffer(OkPacket.OK, c.allocate()));
        break;
    case ServerParse.LOAD_DATA_INFILE_SQL:
           c.loadDataInfileStart(sql);
           break;
    case ServerParse.MIGRATE:
        MigrateHandler.handle(sql,c);
        break;
    case ServerParse.LOCK:
        c.lockTable(sql);
        break;
    case ServerParse.UNLOCK:
        c.unLockTable(sql);
        break;
    default:
        if(readOnly){
            LOGGER.warn(new StringBuilder().append("User readonly:").append(sql).toString());
            c.writeErrMessage(ErrorCode.ER_USER_READ_ONLY, "User readonly");
            break;
        }
        c.execute(sql, rs & 0xff);
    }
}

確定sql的類型

確定sql類型的工作是交給ServerParse.parse(sql);來完成的。ServerParse的算法很簡單,就是一個字符串的匹配過程,下面拿insert和show兩種類型的sql來分析。

insert語句的匹配過程:

static int insertCheck(String stmt, int offset) {
    //因為insert的長度最小是6,所以首先判斷sql語句的長度是不是大于6
    if (stmt.length() > offset + 6) {
        char c1 = stmt.charAt(++offset);
        char c2 = stmt.charAt(++offset);
        char c3 = stmt.charAt(++offset);
        char c4 = stmt.charAt(++offset);
        char c5 = stmt.charAt(++offset);
        char c6 = stmt.charAt(++offset);
        //一個字符一個字符進行匹配
        if ((c1 == 'N' || c1 == 'n') && (c2 == 'S' || c2 == 's')
                && (c3 == 'E' || c3 == 'e') && (c4 == 'R' || c4 == 'r')
                && (c5 == 'T' || c5 == 't')
                && (c6 == ' ' || c6 == '\t' || c6 == '\r' || c6 == '\n')) {
            //【注意】這里是直接返回INSERT
            return INSERT;
        }
    }
    return OTHER;
}

show語句的匹配過程:

static int sCheck(String stmt, int offset) {
    //判斷字符s的下一個字符
    if (stmt.length() > ++offset) {
        switch (stmt.charAt(offset)) {
        case 'A':
        case 'a':
            return savepointCheck(stmt, offset);
        case 'E':
        case 'e':
            return seCheck(stmt, offset);
        case 'H':
        case 'h':
            //下一個字符是s,繼續判斷是不是show
            return showCheck(stmt, offset);
        case 'T':
        case 't':
            return startCheck(stmt, offset);
        default:
            return OTHER;
        }
    }
    return OTHER;
}
// SHOW' '
static int showCheck(String stmt, int offset) {
    //因為show的長度最小是4,并且offset是從字符h開始的,所以首先判斷sql語句的長度是不是大于offset+3
    if (stmt.length() > offset + 3) {
        char c1 = stmt.charAt(++offset);
        char c2 = stmt.charAt(++offset);
        char c3 = stmt.charAt(++offset);
        //逐個字符進行判斷
        if ((c1 == 'O' || c1 == 'o') && (c2 == 'W' || c2 == 'w')
                && (c3 == ' ' || c3 == '\t' || c3 == '\r' || c3 == '\n')) {
            //【注意】這里是offset左移8位再和SHOW進行或操作的結果。
            //這個設計的巧妙之處就在于通過一個返回值,返回了兩個信息:offset和sql類型。
            //唯一需要注意的就是sql類型的常量值不能超過8位,也就是0~255
            return (offset << 8) | SHOW;
        }
    }
    return OTHER;
}
//下面是Mycat目前支持的sql類型對應的常量值。
public static final int OTHER = -1;
public static final int BEGIN = 1;
public static final int COMMIT = 2;
public static final int DELETE = 3;
public static final int INSERT = 4;
public static final int REPLACE = 5;
public static final int ROLLBACK = 6;
public static final int SELECT = 7;
public static final int SET = 8;
public static final int SHOW = 9;
public static final int START = 10;
public static final int UPDATE = 11;
public static final int KILL = 12;
public static final int SAVEPOINT = 13;
public static final int USE = 14;
public static final int EXPLAIN = 15;
public static final int EXPLAIN2 = 151;
public static final int KILL_QUERY = 16;
public static final int HELP = 17;
public static final int MYSQL_CMD_COMMENT = 18;
public static final int MYSQL_COMMENT = 19;
public static final int CALL = 20;
public static final int DESCRIBE = 21;
public static final int LOCK = 22;
public static final int UNLOCK = 23;
public static final int LOAD_DATA_INFILE_SQL = 99;
public static final int DDL = 100;
public static final int MIGRATE  = 203;

經過上面的分析,我們可以看出,ServerParse.parse(sql)的返回值有下面兩種情況:

1.直接返回sql類型。例如INSERT、DDL

2.返回sql類型+offset。例如SHOW、SELECT

所以,對于ServerParse.parse(sql)的返回值,后續的處理方式是下面這樣的。

int rs = ServerParse.parse(sql);
//獲取sql類型
int sqlType = rs & 0xff;
//獲取offset
int offset = rs >>> 8;

將不同類型的sql交給不同的處理器進行處理

SQL的處理方式,大致可以分為下面幾種:

1.對于大部分的sql,都有專門的處理器就行處理。

EXPLAIN——ExplainHandler
EXPLAIN2——Explain2Handler
SET——SetHandler
SHOW——ShowHandler
SELECT——SelectHandler
START——StartHandler
BEGIN——BeginHandler
SAVEPOINT——SavepointHandler
KILL——KillHandler
USE——UseHandler
MIGRATE——MigrateHandler

2.對于不支持的sql,直接返回錯誤信息

KILL_QUERY、HELP

3.Mycat能直接處理掉的,直接處理

COMMIT、ROLLBACK、LOCK、UNLOCK、MYSQL_CMD_COMMENT、MYSQL_COMMENT

4.需要通過MySQL來處理的,執行execute

UPDATE、DELETE、DDL

在動力節點的Mycat教程當中還有更多的內容在等著大家去學習,當然也有相關的配套視頻教程能夠免費下載,課程內容詳細,通俗易懂,適合初學者,希望對大家的學習能夠有所幫助哦。

提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 99久久精品国产免费 | 激情九九| 亚洲精品乱码久久久久 | 亚洲精品高清久久 | 国产精品视频一区二区三区不卡 | 在线麻豆| 老妇毛片久久久久久久久 | 99热这里只有精品国产在热久久 | 久久国产精品夜色 | 国产国产人免费人成成免视频 | 国产免费一区二区三区免费视频 | 亚洲精品乱码一区二区在线观看 | 九九热在线视频 | 日韩久久一区二区三区 | 四虎综合九九色九九综合色 | 欧美一级毛片免费看视频 | 激情五月色播 | 欧美大屁股精品毛片视频 | 免费a大片 | 日韩欧美精品有码在线观看 | 九九视频精品在线 | 日韩一区二区免费视频 | 99热这里只有精品国产动漫 | 四虎国产精品永久在线网址 | 日韩精品一区二区三区国语自制 | 国产亚洲精品久久久久久小说 | 国产一级特黄特色aa毛片 | 99国产精品热久久久久久 | 国产免费不卡v片在线观看 国产免费不卡视频 | 欧美日本在线一区二区三区 | 亚洲精品中文字幕在线 | 久久久久久久久久免免费精品 | 一级理论片免费观看在线 | 日本aaaa级 | 91一区二区在线观看精品 | 日本久久久久久久中文字幕 | 99久久免费国内精品 | 国产欧美一区二区三区精品 | 新久草在线 | 夜夜操天天爽 | 国产精品欧美一区二区 |