如何使用VertxSQL接口合并数据库查询结果
How to merge database query results using Vertx SQL interface
我想使用 Vertx common SQL Interface 从数据库 TDB
中的 table t1
、t2
、t3
查询并与table s1
、s2
、s3
来自数据库 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 documentation。
Future
是异步调用结果的占位符。 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 tConResultFuture
和 Future sConResultFuture
是否成功完成,然后调用其 Handler
。现在两个异步结果都完成了,你可以调用他们的结果了。
你和好东西,两个异步调用是同时完成的。
我想使用 Vertx common SQL Interface 从数据库 TDB
中的 table t1
、t2
、t3
查询并与table s1
、s2
、s3
来自数据库 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 documentation。
Future
是异步调用结果的占位符。 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 tConResultFuture
和 Future sConResultFuture
是否成功完成,然后调用其 Handler
。现在两个异步结果都完成了,你可以调用他们的结果了。
你和好东西,两个异步调用是同时完成的。