1. 问题
读写分离如何执行
2. 源码
ShardingMasterSlaveRouter为核心入口
public SQLRouteResult route(SQLRouteResult sqlRouteResult) { Iterator var2 = this.masterSlaveRules.iterator(); while(var2.hasNext()) { MasterSlaveRule each = (MasterSlaveRule)var2.next(); // 开始路由 this.route(each, sqlRouteResult); } return sqlRouteResult; }
private void route(MasterSlaveRule masterSlaveRule, SQLRouteResult sqlRouteResult) { Collection<RoutingUnit> toBeRemoved = new LinkedList(); Collection<RoutingUnit> toBeAdded = new LinkedList(); Iterator var5 = sqlRouteResult.getRoutingResult().getRoutingUnits().iterator(); while(var5.hasNext()) { RoutingUnit each = (RoutingUnit)var5.next(); if (masterSlaveRule.getName().equalsIgnoreCase(each.getDataSourceName())) { toBeRemoved.add(each); String actualDataSourceName; // 判断是否走主库 if (this.isMasterRoute(sqlRouteResult.getSqlStatementContext().getSqlStatement())) { MasterVisitedManager.setMasterVisited(); actualDataSourceName = masterSlaveRule.getMasterDataSourceName(); } else { // 从库如果有多个,默认是轮询,也可以选择随机访问策略 actualDataSourceName = masterSlaveRule.getLoadBalanceAlgorithm().getDataSource(masterSlaveRule.getName(), masterSlaveRule.getMasterDataSourceName(), new ArrayList(masterSlaveRule.getSlaveDataSourceNames())); } toBeAdded.add(this.createNewRoutingUnit(actualDataSourceName, each)); } } sqlRouteResult.getRoutingResult().getRoutingUnits().removeAll(toBeRemoved); sqlRouteResult.getRoutingResult().getRoutingUnits().addAll(toBeAdded); }
判断是否走主库,包括hint和非查询操作等
private boolean isMasterRoute(SQLStatement sqlStatement) { return this.containsLockSegment(sqlStatement) || !(sqlStatement instanceof SelectStatement) || MasterVisitedManager.isMasterVisited() || HintManager.isMasterRouteOnly(); }
// HintManager可以设置强制走主库,或者非查询操作走主库
RoundRobinMasterSlaveLoadBalanceAlgorithm类执行轮询查询从库策略
// 轮询访问从库 @Override public String getDataSource(final String name, final String masterDataSourceName, final List<String> slaveDataSourceNames) { AtomicInteger count = COUNTS.containsKey(name) ? COUNTS.get(name) : new AtomicInteger(0); COUNTS.putIfAbsent(name, count); count.compareAndSet(slaveDataSourceNames.size(), 0); // 计数器来实现轮询 return slaveDataSourceNames.get(Math.abs(count.getAndIncrement()) % slaveDataSourceNames.size()); }