sharding-jdbc 读写分离的底层实现原理

背景:在做sharding-jdbc读写分离的时候发现其配置非常简单,对于它是如何实现读写分离的,没有一个明确的说明。本文就是为了弄懂,它底层的判断逻辑是什么。网上搜了没发现什么有价值的东西,都是教你如何配置,如何使用,最终的效果。而没有介绍,什么情况下走master,什么情况下走slave。

1、配置及实现

这个可以直接在官网或者网上搜下,有很多介绍其使用方法。


2、底层判断逻辑

在执行到Repository方法的时候,会进入到MasterSlaveRouter,这是重点!直接上段代码。

public final class MasterSlaveRouter {    private final MasterSlaveRule masterSlaveRule;    private final boolean showSQL;    public Collection route(String sql) {        // *** 判断的重点        /**        * 1、new SQLJudgeEngine(sql) 得到一个SQLJudgeEngine的实例        * 2、judge() 重点,见以下代码        */        Collection result = this.route((new SQLJudgeEngine(sql)).judge().getType());        if (this.showSQL) {            SQLLogger.logSQL(sql, result);        }        return result;    }    private Collection route(SQLType sqlType) {        // 判断走master, 还是slave        if (this.isMasterRoute(sqlType)) {            MasterVisitedManager.setMasterVisited();            // 负载均衡            return Collections.singletonList(this.masterSlaveRule.getMasterDataSourceName());        } else {            // 负载均衡            return Collections.singletonList(this.masterSlaveRule.getLoadBalanceAlgorithm().getDataSource(this.masterSlaveRule.getName(), this.masterSlaveRule.getMasterDataSourceName(), new ArrayList(this.masterSlaveRule.getSlaveDataSourceNames())));        }    }    /**    * 三种情况下走master, 主库    * 1、SQL类型不是DQL, 即不是select语句    * 2、masterVisited 等于true, 即可访问,这是一个ThreadLocal,默认初始值是false    * 3、isMasterRouteOnly 是否强制走master库,代码中认为指定    */    private boolean isMasterRoute(SQLType sqlType) {        return SQLType.DQL != sqlType || MasterVisitedManager.isMasterVisited() || HintManager.isMasterRouteOnly();    }    @ConstructorProperties({"masterSlaveRule", "showSQL"})    public MasterSlaveRouter(MasterSlaveRule masterSlaveRule, boolean showSQL) {        this.masterSlaveRule = masterSlaveRule;        this.showSQL = showSQL;    }}

重点跟 judge()

public SQLStatement judge() {    // 根据数据库类型 以及 SQL语句, 实例化一个 LexerEngine    LexerEngine lexerEngine = LexerEngineFactory.newInstance(DatabaseType.MySQL, this.sql);    // 调用父类构造方法,判断并赋值 currentToken 的type    lexerEngine.nextToken();    TokenType tokenType;    do {        tokenType = lexerEngine.getCurrentToken().getType();        if (tokenType instanceof Keyword) {            // 是否是SELECT的枚举类型,返回一个DQL的statement            if (DQLStatement.isDQL(tokenType)) {                return this.getDQLStatement();            }            if (DMLStatement.isDML(tokenType)) {                return this.getDMLStatement(tokenType);            }            if (TCLStatement.isTCL(tokenType)) {                return this.getTCLStatement();            }            if (DALStatement.isDAL(tokenType)) {                return this.getDALStatement(tokenType, lexerEngine);            }            lexerEngine.nextToken();            TokenType secondaryTokenType = lexerEngine.getCurrentToken().getType();            if (DDLStatement.isDDL(tokenType, secondaryTokenType)) {                return this.getDDLStatement();            }            if (DCLStatement.isDCL(tokenType, secondaryTokenType)) {                return this.getDCLStatement();            }            if (TCLStatement.isTCLUnsafe(DatabaseType.MySQL, tokenType, lexerEngine)) {                return this.getTCLStatement();            }            if (DefaultKeyword.SET.equals(tokenType)) {                return new SetStatement();            }        } else {            lexerEngine.nextToken();        }    } while(!(tokenType instanceof Assist) || Assist.END != tokenType);    throw new SQLParsingException("Unsupported SQL statement: [%s]", new Object[]{this.sql});}

说白了,这两段的代码就是根据SQL语句的第一个关键字(select、insert、delete、update)来判断其类型,如果是select则走salve从库,其他的都走master主库。这个是默认的,不能修改,当然可以在代码配置将二者对调,但是这样做事不明智的!

sharding jdbc 读写分离的关键判断

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章