参考1: https://blog.csdn.net/LZN51/article/details/111031194
参考2:https://www.cnblogs.com/binarylei/p/12233756.html
整体运行流程
-
- org.apache.shardingsphere.proxy.Bootstrap.mian()启动;
- AbstractBootstrapInitializer :创建netty3307服务,从该服务器接收到一条指令开始。
- FrontendChannelInboundHandler : 接收客户端指令, 这里会验证是否有登录,如果有登录, 创建一个CommandExecutorTask线程解析指令。核心流程也在这里:
//org.apache.shardingsphere.proxy.frontend.command。CommandExecutorTask#
private boolean executeCommand(final ChannelHandlerContext context, final PacketPayload payload, final BackendConnection backendConnection) throws SQLException {
// 1.获得sql命令执行引擎; DatabaseProtocolFrontendEngine ⽤于ShardingSphere-Proxy 解析与适配访问数据库的协议。
CommandExecuteEngine commandExecuteEngine = databaseProtocolFrontendEngine.getCommandExecuteEngine();
// 2.SQL命令类型;
CommandPacketType type = commandExecuteEngine.getCommandPacketType(payload);
// 3.SQL命令包;
CommandPacket commandPacket = commandExecuteEngine.getCommandPacket(payload, type, backendConnection);
// 4.SQL命令执行器
CommandExecutor commandExecutor = commandExecuteEngine.getCommandExecutor(type, commandPacket, backendConnection);
// 5.SQL命令执行器执行命令并返回结果包;
Collection<DatabasePacket<?>> responsePackets = commandExecutor.execute();
if (responsePackets.isEmpty()) {
return false;
}
// 写入列信息
responsePackets.forEach(context::write);
if (commandExecutor instanceof QueryCommandExecutor) {
// 写入行信息
commandExecuteEngine.writeQueryData(context, backendConnection, (QueryCommandExecutor) commandExecutor, responsePackets.size());
return true;
}
return databaseProtocolFrontendEngine.getFrontendContext().isFlushForPerCommandPacket();
}
- SQL命令执行引擎:
- 看方法实现方法proxy 支持了mysql 和 postgreSql的执行引擎;org.apache.shardingsphere.proxy.frontend.spi.DatabaseProtocolFrontendEngine#getCommandExecuteEngine
- SQL命令类型:
- MySQLCommandPacketType 枚举了所有的MYSQL指令类型, getCommandPacketType 是通过SQL 请求命令包的一个字节来判定 SQL 请求类型。
- MySQLCommandPacketTypeLoader.getCommandPacketType() 与枚举的匹配当前是哪种指令。
- SQL命令包:
- MySQLCommandPacketFactory#newInstance 会根据不同的 SQL 请求类型返回不同的 SQL 命令包。
- SQL命令执行器:
- commandExecuteEngine.getCommandExecutor 也是genuine不同的SQL请求类型返回不同的SQL命令执行器;
- 需要注意的是: 在org.apache.shardingsphere.proxy.backend.text.TextProtocolBackendHandlerFactory#newInstance中:
public static TextProtocolBackendHandler newInstance(final DatabaseType databaseType, final String sql, final BackendConnection backendConnection) {
if (Strings.isNullOrEmpty(sql)) {
return new SkipBackendHandler();
}
// TODO Parse sctl SQL with ANTLR
String trimSQL = SCTLUtils.trimComment(sql);
// 对于前缀为 'SCTL:' 的 SQL 请求,直接返回 ShardingCTLxxxHandler 处理器
if (trimSQL.toUpperCase().startsWith(ShardingCTLBackendHandlerFactory.SCTL)) {
return ShardingCTLBackendHandlerFactory.newInstance(trimSQL, backendConnection);
}
SQLStatement sqlStatement = new ShardingSphereSQLParserEngine(databaseType.getName()).parse(sql, false);
// 建库、删库的sql请求
if (sqlStatement instanceof RDLStatement || sqlStatement instanceof CreateDatabaseStatement || sqlStatement instanceof DropDatabaseStatement) {
return new RDLBackendHandler(backendConnection, sqlStatement);
}
// 事务控制相关请求
if (sqlStatement instanceof TCLStatement) {
return TransactionBackendHandlerFactory.newInstance(sql, (TCLStatement) sqlStatement, backendConnection);
}
//DAL相关请求 show databases,show tables...
if (sqlStatement instanceof DALStatement) {
return DALBackendHandlerFactory.newInstance(sql, (DALStatement) sqlStatement, backendConnection);
}
// 查询请求 直接返回QueryBackendHandler
return new QueryBackendHandler(sql, sqlStatement, backendConnection);
-
- 经过上一步,一条select查询请求使用的是 QueryBackendHandler,使用执行器执行语句则是 org.apache.shardingsphere.proxy.backend.text.query.QueryBackendHandler#execute
- 上一步中execute 获取数据库执行引擎, MySQL 对应 JDBCDatabaseCommunicationEngine。 调用
- org.apache.shardingsphere.proxy.backend.communication.jdbc.JDBCDatabaseCommunicationEngine#execute , 其它过程见下方时序图