1.概述当您看到这个标题时,您可能会有些惊讶。MyCAT可以使用MongoDB作为数据节点。是的,没错,确实如此。HoHoHo,让我们开始这段神奇的“旅程”吧。本文主要分为四个部分:整体流程,让你对查询操作、插入操作彩蛋有一个整体的认识,😈复活节彩蛋,🙂复活节彩蛋我建议你阅读这两篇文章(_不需要_):《MyCAT源码分析 —— 【单库单表】插入》《MyCAT源码分析 —— 【单库单表】查询》2。主进程MyCATServer根据MySQL协议接收MySQLClient的请求,将SQL翻译成MongoDB操作发送给MongoDBServer。MyCATServer接收MongoDBServer返回的MongoDB数据,翻译成MySQL数据返回给MySQLClient。这样MyCAT连接MongoDB就不那么神奇了。Java数据库连接,(JavaDatabaseConnectivity,简称JDBC)是Java语言中使用的一种应用程序编程接口,用于规范客户端程序如何访问数据库,并提供查询和更新数据库中数据等方法。JDBC也是SunMicrosystems的商标。JDBC是面向关系数据库的。MyCAT使用JDBC规范抽象化了对MongoDB的访问。通过这种方式,MyCAT也抽象了SequoiaDB的访问。可能这个说法有点抽象,看个类图就觉得不知所措。是不是很熟悉的味道?不得不说JDBC规范讲究。3、查询操作SELECTid,nameFROMuserWHEREname>''ORDERBY_idDESC;看时序图很方便理解整体逻辑,就不废话了。我们来看几个核心代码逻辑。1)、查询MongoDB//MongoSQLParser.javapublicMongoDataquery()throwsMo??ngoSQLException{if(!(statementinstanceofSQLSelectStatement)){//returnnull;thrownewIllegalArgumentException("notaquerysqlstatement");}MongoDatamongo=newMongoData();DBCursorc=null;SQLSelectStatementselectStmt=(SQLSelectStatement)statement;SQLSelectQuerysqlSelectQuery=selectStmt.getSelect().getQuery();inticount=0;if(sqlSelectQueryinstanceofMySqlSelectQueryBlock){MySqlSelectQueryBlockmysqlSelectQuery=(MySqlSelectQueryBlock)selectStmt.getSelect().getQuery();BasicDBObjectfields=newBasicDBObject();//显示(返回)的段落for(SQLSelectItemitem:mysqlSelectQuery.getSelectList()){//System.out.println(item.toString());if(!(item.getExpr()instanceofSQLAllColumnExpr)){if(item.getExpr()instanceofSQLAggregateExpr){SQLAggregateExprexpr=(SQLAggregateExpr)item.getExpr();if(expr.getMethodName().equals("COUNT")){//TODO阅读:count(*)icount=1;mongo.setField(getExprFieldName(expr),类型.BIGINT);}fields.put(getExprFieldName(expr),1);}else{fields.put(getFieldName(item),1);}}}//表名SQLTableSourcetable=mysqlSelectQuery.getFrom();DBCollectioncoll=this._db.getCollection(table.toString());mongo.setTable(table.toString());//WHERESQLExprexpr=mysqlSelectQuery.getWhere();DBObjectquery=parserWhere(expr);//GROUPBYSQLSelectGroupByClausegroupby=mysqlSelectQuery.getGroupBy();BasicDBObjectgbkey=newBasicDBObject();if(groupby!=null){for(SQLExprgbexpr:groupby.getItems()){if(gbexprinstanceofSQLIdentifierExpr){Stringname=((SQLIdentifierExpr)gbexpr).getName();gbkey.put(name,Integer.valueOf(1));}}icount=2;}//SKIP/LIMITintlimitoff=0;intlimitnum=0;if(mysqlSelectQuery.getLimit()!=null){limitoff=getSQLExprToInt(mysqlSelectQuery.getLimit().getOffset());limitnum=getSQLExprToInt(mysqlSelectQuery.getLimit().getRowCount());}if(icount==1){//COUNT(*)mongo.setCount(coll.count(query));}elseif(icount==2){//MapReduceBasicDBObjectinitial=newBasicDBObject();initial.put("num",0);Stringreduce="function(obj,prev){"+"prev.num++}";mongo.setGrouyBy(coll.group(gbkey,query,initial,reduce));}else{if((limitoff>0)||(limitnum>0)){c=coll.find(query,fields).skip(limitoff).limit(limitnum);}else{c=coll.find(query,fields);}//orderbySQLOrderByorderby=mysqlSelectQuery.getOrderBy();if(orderby!=null){BasicDBObjectorder=newBasicDBObject();for(inti=0;i")){op="$gt";}elseif(expr.getOperator().getName().equals(">=")){op="$gte";}elseif(expr.getOperator().getName().equals("!=")){op="$ne";}elseif(expr.getOperator().getName().equals("<>")){op="$ne";}parserDBObject(o,exprL.toString(),op,getExpValue(expr.getRight()));}}else{if(expr.getOperator().getName().equals("AND")){parserWhere(exprL,o);parserWhere(expr.getRight(),o);}elseif(expr.getOperator().getName().equals("OR")){orWhere(exprL,expr.getRight(),o);}else{thrownewRuntimeException("Can'tidentifytheoperationofwhere");}}}}privatevoidorWhere(SQLExprexprL,SQLExprexprR,BasicDBObjectob){BasicDBobjectxo=newBasicDBObject();BasicDBObjectyo=newBasicDBObject();parserWhere(exprL,xo);parserWhere(exprR,yo);ob.put("$or",newObject[]{xo,yo});}3)、解析MongoDB数据//MongoResultSet.javapublicMongoResultSet(MongoDatamongo,Stringschema)throwsSQLException{this._cursor=mongo.getCursor();this._schema=schema;this._table=mongo.getTable();this.isSum=mongo.getCount()>0;this._sum=mongo.getCount();this.isGroupBy=mongo.getType();if(this.isGroupBy){dblist=mongo.getGrouyBys();this.isSum=true;}if(this._cursor!=null){select=_cursor.getKeysWanted().keySet().toArray(newString[0]);//解析字段if(this._cursor.hasNext()){_cur=_cursor.next();if(_cur!=null){if(select.length==0){SetFields(_cur.keySet());}_row=1;}}//设置字段类型if(select.length==0){select=newString[]{"_id"};SetFieldType(true);}else{SetFieldType(false);}}else{SetFields(mongo.getFields().keySet());//newString[]{"COUNT(*)"};SetFieldType(mongo.getFields());}}使用SELECT*查询字段时,字段使用***即使数据返回的字段在后面的数据中有其他字段,也不会返回。4)、返回数据给MySQLClient//JDBCConnection.javaprivatevoidouputResultSet(ServerConnectionsc,Stringsql)throwsSQLException{ResultSetrs=null;Statementstmt=null;try{stmt=con.createStatement();rs=stmt.executeQuery(sql);//headerListfieldPks=newLinkedList<>();ResultSetUtil.resultSetToFieldPacket(sc.getCharset(),fieldPks,rs,this.isSpark);intcolunmCount=fieldPks.size();ByteBufferbyteBuf=sc.allocate();ResultSetHeaderPacketheaderPkg=newResultSetHeaderPacket();headerPkg.fieldCount=fieldPks.size();headerPkg.packetId=++packetId;byteBuf=headerPkg.write(byteBuf,sc,true);byteBuf.flip();byte[]header=newbyte[byteBuf.limit()];byteBuf.get(header);byteBuf.clear();Listfields=newArrayList(fieldPks.size());for(FieldPacketcurField:fieldPks){curField.packetId=++packetId;byteBuf=curField.write(byteBuf,sc,false);byteBuf.flip();byte[]field=newbyte[byteBuf.limit()];byteBuf.get(field);byteBuf.clear();fields.add(字段);}//headereofEOFPacketeofPckg=newEOFPacket();eofPckg.packetId=++packetId;byteBuf=eofPckg.write(byteBuf,sc,false);byteBuf.flip();byte[]eof=newbyte[byteBuf.limit()];byteBuf.get(eof);byteBuf.clear();this.respHandler.fieldEofResponse(header,fields,eof,this);//rowwhile(rs.next()){RowDataPacketcurRow=newRowDataPacket(colunmCount);for(inti=0;iselect*fromuserorderby_idasc;+------------------------+------+------------------------------+|_id|名称|个人资料|+--------------------------+------+--------------------------------+|1|123|{“年龄”:1,“身高”:100}|4。插入操作//MongoSQLParser.javapublicintexecuteUpdate()throwsMo??ngoSQLException{if(statementinstanceofSQLInsertStatement){returnInsertData((SQLInsertStatement)statement);}if(statementinstanceofSQLUpdateStatement){returnUpData((SQLUpdateStatement)statement);}if(statementinstanceofSQLDropTableStatement){returndropTable((SQLDropTableStatement)statement);}if(statementinstanceofSQLDeleteStatement){returnDeleteDate((SQLDeleteStatement)statement);}if(statementinstanceofSQLCreateTableStatement){returnint1;}returnSQLInsertStatementstate){if(state.getValues().getValues().size()==0){thrownewRuntimeException("numberofcolumnserror");}if(state.getValues().getValues().size()!=state.getColumns().size()){thrownewRuntimeException("numberofvaluesandcolumnshavetomatch");}SQLTableSourcetable=state.getTableSource();BasicDBObjecto=newBasicDBObject();inti=0;for(SQLExprcol:state.getColumns()){o.put(getFieldName2(col),getExpValue(state.getValues().getValues().get(i)));i++;}DBCollectioncoll=this._db.getCollection(table.toString());coll.insert(o);return1;}5.彩蛋1)、支持多个MongoDB,使用MyCAT分片MyCAT配置:multi_mongodb2)、支持MongoDB+MySQL作为同一个MyCATTable的数据节点。查询时,可以合并数据结果。查询时,返回的MySQL数据记录字段必须比MongoDB数据记录字段完整,否则合并结果时会报错。MyCAT配置:single_mongodb_mysql3)、当MongoDB作为数据节点时,可以使用MyCAT提供的数据库主键字段功能。MyCAT配置:single_mongodb