程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Vert-x-經由過程異步的方法應用JDBC銜接SQL

Vert-x-經由過程異步的方法應用JDBC銜接SQL

編輯:關於JAVA

Vert-x-經由過程異步的方法應用JDBC銜接SQL。本站提示廣大學習愛好者:(Vert-x-經由過程異步的方法應用JDBC銜接SQL)文章只能為提供參考,不一定能成為您想要的結果。以下是Vert-x-經由過程異步的方法應用JDBC銜接SQL正文


在這篇文章中,我們將會看到如何在vert.x運用中應用HSQL,固然也能夠應用隨意率性JDBC,和應用vertx-jdbc-client供給的異步的API,這篇文章的代碼在github。

異步?

vert.x一個很主要的特色就是它的異步性。應用異步的API,不須要等成果前往,當有成果前往時,vert.x會自動告訴。為了解釋這個,我們來看一個簡略的例子。

我們假定有個add辦法。普通來講,會像int r = add(1, 1)如許來應用它。這是一個同步的API,所以你必需比及前往成果。異步的API會是如許:add(1, 1, r -> { /*do something with the result*/})。在這個版本中,你傳入了一個Handler,當成果盤算出來時才被挪用。這個辦法不前往任何器械,完成以下:

public void add(int a, int b, Handler<Integer> resultHandler) {
int r = a + b;
resultHandler.handle(r);
}

為了不混雜概念,異步API其實不是多線程。像我們在add例子裡看到的,並沒有觸及多線程。

異步JDBC

看了一些根本的異步的API,如今懂得下vertx-jdbc-client。這個組件可以或許讓我們經由過程JDBC driver與數據庫交互。這些交互都是異步的,之前如許:

String sql = "SELECT * FROM Products";
ResultSet rs = stmt.executeQuery(sql);

如今要如許:

connection.query("SELECT * FROM Products", result -> {
// do something with the result
});

這個模子更高效,當成果出來後vert.x告訴,防止了期待成果。

增長maven依附

在pom.xml文件中增長兩個 Maven dependencies

<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-jdbc-client</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.3</version>
</dependency>

第一個依附供給了vertx-jdbc-client,第二個供給了HSQL JDBC的驅動。假如你想應用別的一個數據庫,修正這個依附,同時你還須要修正JDBC url和JDBC driver名。

初始化JDBC client

創立JDBC 客戶端(client):

在MyFirstVerticle類中,聲明一個新變量JDBCClient jdbc,而且在start辦法中添加:

jdbc = JDBCClient.createShared(vertx, config(), "My-Whisky-Collection");

創立了一個JDBC client實例,應用verticle的設置裝備擺設文件設置裝備擺設JDBC client。這個設置裝備擺設文件須要供給上面的設置裝備擺設能力讓JDBC client正常任務:

url-JDBC url,例如:jdbc:hsqldb:mem:db?shutdown=true
_driver class-JDBC的驅動,例如:org.hsqldb.jdbcDriver

有了client,接上去須要銜接數據庫。銜接數據庫是經由過程應用jdbc.getConnection來完成的,jdbc.getConnection須要傳入一個Handler<AsyncResult<SQLConnection>>參數。我們深刻的懂得下這個類型。起首,這是一個Handler,是以當成果預備好時它就會被挪用。這個成果是AsyncResult<SQLConnection>的一個實例。AsyncResult是vert.x供給的一個構造,應用它可以或許曉得銜接數據庫的操作是勝利或掉敗了。假如勝利了,它就會供給一個成果,這裡成果是一個SQLConnection的實例。

當你吸收一個AsyncResult的實例時,代碼平日是:

if (ar.failed()) {
System.err.println("The operation has failed...: "
+ ar.cause().getMessage());
} else {
// Use the result:
result = ar.result();
}

須要獲得到SQLConnection,然後啟動rest的運用。由於釀成了異步的,這須要轉變啟動運用的方法。是以,假如將啟動序列劃分紅多塊:

startBackend(
(connection) -> createSomeData(connection,
(nothing) -> startWebApp(
(http) -> completeStartup(http, fut)
), fut
), fut);

startBackend- 獲得SQLConnection對象,然後挪用下一步
createSomeData- 初始化數據庫並拔出數據。當完成後,挪用下一步
startWebApp- 啟動web運用
completeStartup- 最初完成啟動
fut由vert.x傳入,告訴曾經啟動或許啟動進程中碰到的成績。

startBackend辦法:

private void startBackend(Handler<AsyncResult<SQLConnection>> next, Future<Void> fut) {
jdbc.getConnection(ar -> {
if (ar.failed()) {
fut.fail(ar.cause());
} else {
next.handle(Future.succeededFuture(ar.result()));
}
});
}

這個辦法獲得了一個SQLConnection對象,檢討操作能否完成。假如勝利,會挪用下一步。掉敗了,就會申報一個毛病。其他的辦法遵守異樣的形式:

檢討上一步操作能否勝利

處置營業邏輯

挪用下一步

SQL

客戶端曾經預備好了,如今寫SQL。從createSomeData辦法開端,這個辦法也是啟動次序中的一部門:

private void createSomeData(AsyncResult<SQLConnection> result,
Handler<AsyncResult<Void>> next, Future<Void> fut) {
if (result.failed()) {
fut.fail(result.cause());
} else {
SQLConnection connection = result.result();
connection.execute(
"CREATE TABLE IF NOT EXISTS Whisky (id INTEGER IDENTITY, name varchar(100), " +
"origin varchar(100))",
ar -> {
if (ar.failed()) {
fut.fail(ar.cause());
connection.close();
return;
}
connection.query("SELECT * FROM Whisky", select -> {
if (select.failed()) {
fut.fail(ar.cause());
connection.close();
return;
}
if (select.result().getNumRows() == 0) {
insert(
new Whisky("Bowmore 15 Years Laimrig", "Scotland, Islay"),
connection,
(v) -> insert(new Whisky("Talisker 57° North", "Scotland, Island"),
connection,
(r) -> {
next.handle(Future.<Void>succeededFuture());
connection.close();
})); 
} else {
next.handle(Future.<Void>succeededFuture());
connection.close();
}
});
});
}
}

這個辦法檢討SQLConnection能否可用,然後履行一些SQL語句。起首,假如表不存在就創立表。看看上面代碼:

connection.execute(
SQL statement,
handler called when the statement has been executed
)

handler吸收AsyncResult<Void>,例如:只要是告訴罷了,沒有現實前往的成果。

封閉銜接

操作完成後,別忘了封閉SQL鏈接。這個銜接會被放入銜接池而且可以被反復應用。

在這個handler的代碼裡,檢討了statement能否准確的履行了,假如准確,我們接上去檢討表能否含稀有據,假如沒有,將會應用insert辦法拔出數據:

private void insert(Whisky whisky, SQLConnection connection, Handler<AsyncResult<Whisky>> next) {
String sql = "INSERT INTO Whisky (name, origin) VALUES ?, ?";
connection.updateWithParams(sql,
new JsonArray().add(whisky.getName()).add(whisky.getOrigin()),
(ar) -> {
if (ar.failed()) {
next.handle(Future.failedFuture(ar.cause()));
return;
}
UpdateResult result = ar.result();
// Build a new whisky instance with the generated id.
Whisky w = new Whisky(result.getKeys().getInteger(0), whisky.getName(), whisky.getOrigin());
next.handle(Future.succeededFuture(w));
});
}

這個辦法應用帶有INSERT(拔出)statement(聲明)的upateWithParams辦法,且傳入了值。這個辦法防止了SQL注入。一旦statement履行了(當數據庫沒有此條數據就會創立),就創立一個新的Whisky對象,主動生成ID。

帶稀有據庫(SQL)的REST

下面的辦法都是啟動次序的一部門。然則,關於挪用REST API的辦法又是怎樣樣的呢?以getAll辦法為例。這個辦法被web運用前端挪用,並檢索存儲的一切的產物:

private void getAll(RoutingContext routingContext) {
jdbc.getConnection(ar -> {
SQLConnection connection = ar.result();
connection.query("SELECT * FROM Whisky", result -> {
List<Whisky> whiskies = result.result().getRows().stream().map(Whisky::new).collect(Collectors.toList());
routingContext.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(whiskies));
connection.close(); // Close the connection 
});
});
}

這個辦法取得了一個SQLConnection對象,然後收回一個查詢。一旦獲得到查詢成果,它會像之前的辦法一樣寫HTTP response。getOne、deleteOne、updateOne和addOne辦法都是一樣的。留意,在response以後,須要要封閉SQL銜接。

看下傳入到query辦法的handler供給的成果。獲得了一個包括了查詢成果的ResultSet。每行都是一個JsonObject,是以,假如你有一個數據對象應用JsonObject作為獨一的參數,那末創立這個對象很簡略。

測試

須要小小的更新下測試法式,增長設置裝備擺設JDBCClient。在MyFirstVerticleTest類中,將setUp辦法中創立的DeploymentOption對象修正成:

DeploymentOptions options = new DeploymentOptions()
.setConfig(new JsonObject()
.put("http.port", port)
.put("url", "jdbc:hsqldb:mem:test?shutdown=true")
.put("driver_class", "org.hsqldb.jdbcDriver")
);

除http.port,還設置裝備擺設了JDBC url和JDBC驅動。測試時,應用的是一個內存數據庫。在src/test/resources/my-it-config.json文件中也要做異樣的修正。

{
"http.port": ${http.port},
"url": "jdbc:hsqldb:mem:it-test?shutdown=true",
"driver_class": "org.hsqldb.jdbcDriver"
}

src/main/conf/my-application-conf.json文件也異樣須要修正,這不是為了測試,而是為了運轉這個運用:

{
"http.port" : 8082,
"url": "jdbc:hsqldb:file:db/whiskies",
"driver_class": "org.hsqldb.jdbcDriver"
}

這裡這個JDBC url和上一個文件的有點紛歧樣,由於須要將數據庫存儲到硬盤中。

展現時光!

開端構建法式:

mvn clean package

沒有修正API(沒有更改宣布的java文件和REST接口),測試應當是可以順遂的運轉的。

啟動運用:

java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar -conf src/main/conf/my-application-conf.json

拜訪http://localhost:8082/assets/index.html,然後,你可以看到這個運用應用的是數據庫了。這一次,就算重啟運用,這些數據依然在,由於存儲產物被耐久化到硬盤裡了。

總結

這篇文章中,曉得了怎樣在vert.x裡應用JDBC數據庫,並沒有許多龐雜的器械。開端能夠會被這個異步的開辟模子驚奇到,然則,一旦你開端應用了,你就很難再歸去了。

下一次,我們將看到這個運用怎樣應用mongoDB來調換HSQL。

迎接存眷<a href="http://quanke.name/"  rel="nofollow" ></a>

交換群:231419585

轉載請注明出處,感謝

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved