背景:在做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 条评论) “” |