如何使用VertxSQL接口合并数据库查询结果

How to merge database query results using Vertx SQL interface

我想使用 Vertx common SQL Interface 从数据库 TDB 中的 table t1t2t3 查询并与table s1s2s3 来自数据库 SDB 和 return 它们作为 JsonObject。最后的结果应该是这样的

{
    "t1": [{...},{...},...],
    "t2": [{...},{...},...],
    "t3": [{...},{...},...],
    "s1": [{...},{...},...],
    "s2": [{...},{...},...],
    "s3": [{...},{...},...]
}

如果只有一个table,我会这样做

JDBCClient tdbClient = JDBCClient.createShared(vertx, tdbConfig, "TDB");
JDBCClient sdbClient = JDBCClient.createShared(vertx, sdbConfig, "SDB");
vertx.eventBus().consumer("myservice.getdata").handler(msg -> {
    tdbClient.getConnection(tConresult -> { 
        if (tConresult.succeeded()) {
            SQLConnection tConnection = tConresult.result();
            tConnection.query("select * from t1", t1 -> { 
                if (t1.succeeded()) {
                    JsonArray t1Result = new JsonArray(t1.result().getRows());
                    JsonObject allResult = new JsonObject()
                        .put("t1", t1Result);
                    msg.reply(allResult);
                } else {
                    msg.fail(1, "failt to query t1");
                }
            });
        } else {
            msg.fail(1, "connot get connection to TDB");
        }
    });
});

但是因为它必须有很多table,所以我找到了这样一个丑陋的方式

vertx.eventBus().consumer("myservice.getdata").handler(msg -> {
    tdbClient.getConnection(tConresult -> { if (tConresult.succeeded()) {
    sdbClient.getConnection(sConresult -> { if (sConresult.succeeded()) {
    SQLConnection tConnection = tConresult.result();
    SQLConnection sConnection = sConresult.result();
        tConnection.query("select * from t1", t1 -> { if (t1.succeeded()) {
        tConnection.query("select * from t2", t2 -> { if (t2.succeeded()) {
        tConnection.query("select * from t3", t3 -> { if (t3.succeeded()) {
        sConnection.query("select * from s1", s1 -> { if (s1.succeeded()) {
        sConnection.query("select * from s2", s2 -> { if (s2.succeeded()) {
        sConnection.query("select * from s3", s3 -> { if (s3.succeeded()) {
            JsonArray t1Result = new JsonArray(t1.result().getRows());
            JsonArray t2Result = new JsonArray(t2.result().getRows());
            JsonArray t3Result = new JsonArray(t3.result().getRows());
            JsonArray s1Result = new JsonArray(s1.result().getRows());
            JsonArray s2Result = new JsonArray(s2.result().getRows());
            JsonArray s3Result = new JsonArray(s3.result().getRows());
            JsonObject allResult = new JsonObject()
                .put("t1", t1Result)
                .put("t2", t2Result)
                .put("t3", t3Result)
                .put("s1", s1Result)
                .put("s2", s2Result)
                .put("s3", s3Result);
            msg.reply(allResult);
        } else {msg.fail(1, "failt to query s3");}});
        } else {msg.fail(1, "failt to query s2");}});
        } else {msg.fail(1, "failt to query s1");}});
        } else {msg.fail(1, "failt to query t3");}});
        } else {msg.fail(1, "failt to query t2");}});
        } else {msg.fail(1, "failt to query t1");}});
    } else {msg.fail(1, "connot get connection to SDB");}});
    } else {msg.fail(1, "connot get connection to TDB");}});
});

但我认为我做错了,尽管代码很丑陋,但处理起来会花费很多时间,因为它不会并行执行查询。

请提出更好的实现方法。

您在这里遇到的是callback hell. Vert.x provides some features to handle AsyncResult in a much more composable and convient way than callbacks. They are called Future. I suggest you read about them in the documentationFuture 是异步调用结果的占位符。 Vert.x 充满了异步调用。如果异步调用相互依赖,您通常会陷入回调地狱。使用 Future 你可以这样做:

Future<SQLConnection> tConResultFuture = Future.future();
tdbClient.getConnection(tConresult -> {
  if (tConresult.succeeded()) {
    logger.info("Yeah got a connection! tCon");
    tConResultFuture.complete(tConresult.result());
  } else {
    tConResultFuture.fail(tConresult.cause());
  }
});

AsyncResult<SQLConnection>Handler 将获取 SQLConnection 的异步结果放入 Future tConResultFuture。现在您可以为 Future 设置 Handler 并等待 getConnection:

的异步结果
tConResultFuture.setHandler(result -> {
  // ...
});

但这并没有多大意义,因为您已经可以在第一个 Handler 中做到这一点。现在想想像你这样的例子——有很多依赖 Futures。我使用您的示例添加第二个连接 – sConresult:

Future<SQLConnection> sConResultFuture = Future.future();
sdbClient.getConnection(sConresult -> {
  if (sConresult.succeeded()) {
    logger.info("Yeah got a connection! sCon");
    sConResultFuture.complete(sConresult.result());
  } else {
    sConResultFuture.fail(sConresult.cause());
  }
});

所以可以说,您想等待两个 Future 结果,因为它们相互依赖。这里我们使用 Vert.x' CompositeFuture:

CompositeFuture.all(tConResultFuture, sConResultFuture).setHandler(connections -> {
  if (connections.succeeded()) {
    logger.info("Both connections are ready for use!");

    SQLConnection tCon = tConResultFuture.result();
    SQLConnection sCon = sConResultFuture.result();

    // do stuff...
  } else {
    logger.severe("Both or one connections attempt failed!");
  }
});

CompositeFuture 等待 Future tConResultFutureFuture sConResultFuture 是否成功完成,然后调用其 Handler。现在两个异步结果都完成了,你可以调用他们的结果了。

你和好东西,两个异步调用是同时完成的。