欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vert-x-通過異步的方式使用JDBC連接SQL

 更新時(shí)間:2016年01月18日 10:28:57   作者:不安分的碼農(nóng)  
在這篇文章中,我們將會看到怎樣在vert.x應(yīng)用中使用HSQL,當(dāng)然也可以使用任意JDBC,以及使用vertx-jdbc-client提供的異步的API,這篇文章的代碼在github

在這篇文章中,我們將會看到怎樣在vert.x應(yīng)用中使用HSQL,當(dāng)然也可以使用任意JDBC,以及使用vertx-jdbc-client提供的異步的API,這篇文章的代碼在github。

異步?

vert.x一個(gè)很重要的特點(diǎn)就是它的異步性。使用異步的API,不需要等結(jié)果返回,當(dāng)有結(jié)果返回時(shí),vert.x會主動通知。為了說明這個(gè),我們來看一個(gè)簡單的例子。

我們假設(shè)有個(gè)add方法。一般來說,會像int r = add(1, 1)這樣來使用它。這是一個(gè)同步的API,所以你必須等到返回結(jié)果。異步的API會是這樣:add(1, 1, r -> { /*do something with the result*/})。在這個(gè)版本中,你傳入了一個(gè)Handler,當(dāng)結(jié)果計(jì)算出來時(shí)才被調(diào)用。這個(gè)方法不返回任何東西,實(shí)現(xiàn)如下:

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

為了避免混淆概念,異步API并不是多線程。像我們在add例子里看到的,并沒有涉及多線程。

異步JDBC

看了一些基本的異步的API,現(xiàn)在了解下vertx-jdbc-client。這個(gè)組件能夠讓我們通過JDBC driver與數(shù)據(jù)庫交互。這些交互都是異步的,以前這樣:

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

現(xiàn)在要這樣:

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

這個(gè)模型更高效,當(dāng)結(jié)果出來后vert.x通知,避免了等待結(jié)果。

增加maven依賴

在pom.xml文件中增加兩個(gè) 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>

第一個(gè)依賴提供了vertx-jdbc-client,第二個(gè)提供了HSQL JDBC的驅(qū)動。如果你想使用另外一個(gè)數(shù)據(jù)庫,修改這個(gè)依賴,同時(shí)你還需要修改JDBC url和JDBC driver名。

初始化JDBC client

創(chuàng)建JDBC 客戶端(client):

在MyFirstVerticle類中,聲明一個(gè)新變量JDBCClient jdbc,并且在start方法中添加:

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

創(chuàng)建了一個(gè)JDBC client實(shí)例,使用verticle的配置文件配置JDBC client。這個(gè)配置文件需要提供下面的配置才能讓JDBC client正常工作:

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

有了client,接下來需要連接數(shù)據(jù)庫。連接數(shù)據(jù)庫是通過使用jdbc.getConnection來實(shí)現(xiàn)的,jdbc.getConnection需要傳入一個(gè)Handler<AsyncResult<SQLConnection>>參數(shù)。我們深入的了解下這個(gè)類型。首先,這是一個(gè)Handler,因此當(dāng)結(jié)果準(zhǔn)備好時(shí)它就會被調(diào)用。這個(gè)結(jié)果是AsyncResult<SQLConnection>的一個(gè)實(shí)例。AsyncResult是vert.x提供的一個(gè)結(jié)構(gòu),使用它能夠知道連接數(shù)據(jù)庫的操作是成功或失敗了。如果成功了,它就會提供一個(gè)結(jié)果,這里結(jié)果是一個(gè)SQLConnection的實(shí)例。

當(dāng)你接收一個(gè)AsyncResult的實(shí)例時(shí),代碼通常是:

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

需要獲取到SQLConnection,然后啟動rest的應(yīng)用。因?yàn)樽兂闪水惒降?,這需要改變啟動應(yīng)用的方式。因此,如果將啟動序列劃分成多塊:

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

startBackend- 獲取SQLConnection對象,然后調(diào)用下一步
createSomeData- 初始化數(shù)據(jù)庫并插入數(shù)據(jù)。當(dāng)完成后,調(diào)用下一步
startWebApp- 啟動web應(yīng)用
completeStartup- 最后完成啟動
fut由vert.x傳入,通知已經(jīng)啟動或者啟動過程中遇到的問題。

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()));
}
});
}

這個(gè)方法獲取了一個(gè)SQLConnection對象,檢查操作是否完成。如果成功,會調(diào)用下一步。失敗了,就會報(bào)告一個(gè)錯(cuò)誤。其他的方法遵循同樣的模式:

檢查上一步操作是否成功

處理業(yè)務(wù)邏輯

調(diào)用下一步

SQL

客戶端已經(jīng)準(zhǔn)備好了,現(xiàn)在寫SQL。從createSomeData方法開始,這個(gè)方法也是啟動順序中的一部分:

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();
}
});
});
}
}

這個(gè)方法檢查SQLConnection是否可用,然后執(zhí)行一些SQL語句。首先,如果表不存在就創(chuàng)建表??纯聪旅娲a:

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

handler接收AsyncResult<Void>,例如:只有是通知而已,沒有實(shí)際返回的結(jié)果。

關(guān)閉連接

操作完成后,別忘了關(guān)閉SQL鏈接。這個(gè)連接會被放入連接池并且可以被重復(fù)利用。

在這個(gè)handler的代碼里,檢查了statement是否正確的執(zhí)行了,如果正確,我們接下來檢查表是否含有數(shù)據(jù),如果沒有,將會使用insert方法插入數(shù)據(jù):

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));
});
}

這個(gè)方法使用帶有INSERT(插入)statement(聲明)的upateWithParams方法,且傳入了值。這個(gè)方法避免了SQL注入。一旦statement執(zhí)行了(當(dāng)數(shù)據(jù)庫沒有此條數(shù)據(jù)就會創(chuàng)建),就創(chuàng)建一個(gè)新的Whisky對象,自動生成ID。

帶有數(shù)據(jù)庫(SQL)的REST

上面的方法都是啟動順序的一部分。但是,關(guān)于調(diào)用REST API的方法又是怎么樣的呢?以getAll方法為例。這個(gè)方法被web應(yīng)用前端調(diào)用,并檢索存儲的所有的產(chǎn)品:

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 
});
});
}

這個(gè)方法獲得了一個(gè)SQLConnection對象,然后發(fā)出一個(gè)查詢。一旦獲取到查詢結(jié)果,它會像之前的方法一樣寫HTTP response。getOne、deleteOne、updateOne和addOne方法都是一樣的。注意,在response之后,需要要關(guān)閉SQL連接。

看下傳入到query方法的handler提供的結(jié)果。獲取了一個(gè)包含了查詢結(jié)果的ResultSet。每一行都是一個(gè)JsonObject,因此,如果你有一個(gè)數(shù)據(jù)對象使用JsonObject作為唯一的參數(shù),那么創(chuàng)建這個(gè)對象很簡單。

測試

需要小小的更新下測試程序,增加配置JDBCClient。在MyFirstVerticleTest類中,將setUp方法中創(chuàng)建的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驅(qū)動。測試時(shí),使用的是一個(gè)內(nèi)存數(shù)據(jù)庫。在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文件也同樣需要修改,這不是為了測試,而是為了運(yùn)行這個(gè)應(yīng)用:

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

這里這個(gè)JDBC url和上一個(gè)文件的有點(diǎn)不一樣,因?yàn)樾枰獙?shù)據(jù)庫存儲到硬盤中。

展示時(shí)間!

開始構(gòu)建程序:

mvn clean package

沒有修改API(沒有更改發(fā)布的java文件和REST接口),測試應(yīng)該是可以順利的運(yùn)行的。

啟動應(yīng)用:

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,然后,你可以看到這個(gè)應(yīng)用使用的是數(shù)據(jù)庫了。這一次,就算重啟應(yīng)用,這些數(shù)據(jù)仍然在,因?yàn)榇鎯Ξa(chǎn)品被持久化到硬盤里了。

總結(jié)

這篇文章中,知道了怎么在vert.x里使用JDBC數(shù)據(jù)庫,并沒有很多復(fù)雜的東西。開始可能會被這個(gè)異步的開發(fā)模型驚訝到,但是,一旦你開始使用了,你就很難再回去了。

下一次,我們將看到這個(gè)應(yīng)用怎么使用mongoDB來替換HSQL。

歡迎關(guān)注<a href="

交流群:231419585

轉(zhuǎn)載請注明出處,謝謝

相關(guān)文章

  • Java生成二維碼可添加logo和文字功能

    Java生成二維碼可添加logo和文字功能

    這篇文章主要介紹了Java生成二維碼可添加logo和文字功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • Spring注解和同步鎖不能同步問題解決

    Spring注解和同步鎖不能同步問題解決

    這篇文章主要介紹了Spring注解和同步鎖不能同步問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 2021年最新Redis面試題匯總(4)

    2021年最新Redis面試題匯總(4)

    在程序員面試過程中redis相關(guān)的知識是常被問到的話題。這篇文章主要介紹了幾道Redis面試題,整理一下分享給大家,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 幾種JAVA細(xì)粒度鎖的實(shí)現(xiàn)方式

    幾種JAVA細(xì)粒度鎖的實(shí)現(xiàn)方式

    這篇文章主要為大家詳細(xì)介紹了幾種JAVA細(xì)粒度鎖的實(shí)現(xiàn)方式,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Java Lambda 表達(dá)式源碼解析

    Java Lambda 表達(dá)式源碼解析

    這篇文章主要介紹了Java Lambda在JVM中是如何實(shí)現(xiàn)的,感興趣的小伙伴一起來了解了解
    2021-08-08
  • MyBatis框架迭代器模式實(shí)現(xiàn)原理解析

    MyBatis框架迭代器模式實(shí)現(xiàn)原理解析

    這篇文章主要介紹了MyBatis框架迭代器模式實(shí)現(xiàn)原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java通過索引值實(shí)現(xiàn)約瑟夫環(huán)算法

    Java通過索引值實(shí)現(xiàn)約瑟夫環(huán)算法

    這篇文章主要介紹了Java通過索引值實(shí)現(xiàn)約瑟夫環(huán),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Spring Boot + Mybatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的方法

    Spring Boot + Mybatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的方法

    這篇文章主要介紹了Spring Boot + Mybatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • IDEA 中創(chuàng)建并部署 JavaWeb 程序的方法步驟(圖文)

    IDEA 中創(chuàng)建并部署 JavaWeb 程序的方法步驟(圖文)

    本文主要介紹了IDEA 中創(chuàng)建并部署 JavaWeb 程序的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • SpringMVC中的http Caching的具體使用

    SpringMVC中的http Caching的具體使用

    本文主要介紹了SpringMVC中的http Caching的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論