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
轉載請注明出處,感謝