Vert.x有毛病?

問題:

在Vert.x中寫sql很囉嗦,然後發現最新版本3.4.1不支持batch操作,over,我的天~

網上查了下,別人總結了其他一些問題,蠻好。存起來看看。

原文地址Vert.x的一些問題

以下純複製粘貼

1.vertx使用共享資源產生的重複代碼

在vertx中,verticle是最基本的結構,簡單的說類似j2ee servlet,但是verticle更加靈活,不僅可以是服務,也可是客戶端,verticle之間通過eventbus通訊,實際上更類似akka的actor,vertx實現了類似nodejs express風格的web框架,但是java是多線程的,通常java的面向的目標環境更復雜。這樣產生了一系列問題。如jdbc連接池,在創建的時候必須在 verticle的start 中引入類似的語句

JDBCClient client = JDBCClient.createShared(vertx, new JsonObject().clear()
                .put("provider_class", "io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider")
                .put("jdbcUrl", "jdbc:postgresql://127.0.0.1:5432/mydb")
                .put("username", "postgres")
                .put("password","password")
                .put("driverClassName", "org.postgresql.Driver")
                .put("maximumPoolSize", 30),"mypool");

如果有另外一個verticle 需要使用連接池 mypool,也必須在start方法中加入這樣一段。verticle 部署的是異步的多線程環境,這個createShared方法必須是線程安全的。如果有很多程序需要使用這個連接池 mypool,就會產生大量的冗餘代碼,這段代碼必須是線程安全的。一個可行的方案是創建一個configuration verticle,這個verticle初始化所有的共享資源。然後通過這個verticle的靜態方法訪問系統的所有的共享資源。這樣會減少大量的冗餘代碼,作爲單例類,也不必是線程安全的。

需要注意是 當使用 vertx.deployVerticle 部署verticle (vertx是可以理解爲一個verticle的環境),不能保證verticle的運行順序,部署是異步的。爲了保證configuration verticle的在其他verticle之前運行,必須使部署過程同步。同步方法並不複雜,可以用future實現。

try {
    log.info("deploy " + verticleID);
    CompletableFuture<Integer> future = new CompletableFuture<Integer>();
    vertx.deployVerticle(verticleID, deploymentOptions, res -> {
    if (res.succeeded()) {
        log.info("Deployment id is: " + res.result());
        future.complete(1);
    } else {
        log.error("Deployment failed!");
        future.complete(0);
    }});
    int result = future.get();
} catch (Throwable t) {
    log.error("error", t);
}

2.異步jdbc

異步jdbc確實能夠提高效率,vertx提供了基於sql 語句的異步api,下面是從vertx jdbc example 摘下來的一個例子。

// create a test table
      execute(conn.result(), "create table test(id int primary key, name varchar(255))", create -> {
        // start a transaction
        startTx(conn.result(), beginTrans -> {
          // insert some test data
          execute(conn.result(), "insert into test values(1, 'Hello')", insert -> {
            // commit data
            endTx(conn.result(), commitTrans -> {
              // query some data
              query(conn.result(), "select count(*) from test", rs -> {
                for (JsonArray line : rs.getResults()) {
                  System.out.println(line.encode());
                }

                // and close the connection
                conn.result().close(done -> {
                  if (done.failed()) {
                    throw new RuntimeException(done.cause());
                  }
                });
              });
            });
          });
        });
      });
    });
  }

這是一個非常簡單的事務,都需要寫成這樣,無法想象一個複雜事務的處理程序會變成什麼樣子。其實jdbc driver api依然是同步的,不過vertx提供了一個異步封裝。語句級別異步api過細,如果程序員能夠自己控制異步的粒度,將會改善這種情況。我的方案是提供jdbc同步api,然後程序員可以異步封裝一個過程。這在vertx很容易實現。

executor.executeBlocking((Future<T> f) -> {
      try {
          jdbc_routine();
        }
        f.complete();
      } catch (SQLException e) {
        f.fail(e);
      }
    }, handler);

小結 vertx的體系結構無疑是非常先進的,多線程異步結構,內置metrics,支持cluster,支持高可用度,這些都不是nodejs輕易能夠提供的。 但是目前使用起來確實有諸多不變,需要一點hack。


對作者說的異步的callback holl的抱怨,有點不贊同。不是提供了Future.compose方法麼,如下:

getConnection()
        .compose(conn -> {
            Future someOperation1 = Future.future();
            conn.queryWithParams(query, new JsonArray(), someOperation1);
            someOperation1
                    .compose(ar -> {
                        ResultSet rs = (ResultSet)ar;
                        List<JsonObject> jsonList = rs.getRows();
                        Future someOperation2 = Future.future();
                        conn.queryWithParams(query, new JsonArray(), someOperation2);
                        return someOperation2;
                    })
                    .compose(ar2 -> {
                        ResultSet rs = (ResultSet)ar2;
                        List<JsonObject> jsonList = rs.getRows();
                        Future someOperation3 = Future.future();
                        conn.queryWithParams(query, new JsonArray(), someOperation3);
                        return someOperation3;
                    }).compose(ar3 -> {
                        ResultSet rs = (ResultSet)ar3;
                        List<JsonObject> jsonList = rs.getRows();
                        Future someOperationEnd = Future.future();
                        conn.queryWithParams(query, new JsonArray(), someOperationEnd);
                        return someOperationEnd;
                    });
}, updateResFut);
return updateResFut;
這樣也不會出現那個問題了。待更新ing ...


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章