quarkus數據庫篇之二:無需數據庫也能運行增刪改查(dev模式)

歡迎訪問我的GitHub

這裏分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos

本篇概覽

  • 本篇內容並非數據庫相關的核心知識,而是對一個實用工具的說明介紹,此工具在官方介紹中被稱爲Zero Config Setup (Dev Services),(零配置的設置,忒莫名其妙)

  • 我這邊簡單總結爲:如果你沒有數據庫可用,只要你有docker,quarkus應用就能進行數據庫相關的開發工作,增刪改查啥都行,和有數據庫的時候沒啥區別

  • 看到這裏,經驗豐富的您應該會覺得:既然有docker,那麼用docker run裝一個數據庫不就行了嗎,和quarkus工具有啥關係?

  • 其實這個Zero Config Setup還算是有那麼一點自己的特色,和自己動手在docker中裝數據庫有一丟丟區別,我做了個對比圖如下

流程图 (5)
  • 可見Zero Config Setup的好處是啥都不用配,有docker就行,劣勢是必須要用mvn quarkus:dev啓動應用,profile固定是dev

  • 看到這裏,您是否會這麼覺得:哦,知道了,那我去建一個application-dev.properites文件,裏面沒有數據庫配置,然後執行mvn quarkus:dev啓動應用就行了,就這點內容唄,欣宸你別寫了,太囉嗦...

  • 確實內容少,但是它有坑啊,所以請您隨本文一同實戰吧,等到操作成功的那一刻,新技能get帶來的舒適感相信您也不會拒絕,然後用起Zero Config Setup直呼666

  • 接下來咱們親自動手體驗這個Zero Config Setup,看看適不適合開發階段使用

關於數據庫操作的源碼

名稱 鏈接 備註
項目主頁 https://github.com/zq2599/blog_demos 該項目在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該項目源碼的倉庫地址,https協議
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該項目源碼的倉庫地址,ssh協議
  • 這個git項目中有多個文件夾,本次實戰的源碼在quarkus-tutorials文件夾下,如下圖紅框
    image-20220312091203116
  • quarkus-tutorials是個父工程,裏面有多個module,本篇實戰的module是basic-db,如下圖紅框
    image-20220504102912592

提前下載docker鏡像

  • 建議先把鏡像下載到本地才能使用Zero Config Setup功能,否則如果等quarkus框架自動下載鏡像,可能會有如下錯誤發生
[INFO] Compiling 1 source file to /Users/zhaoqin/github/blog_demos/quarkus-tutorials/basic-db/target/test-classes
Listening for transport dt_socket at address: 5005
2022-05-08 10:52:56,714 ERROR [com.git.doc.api.asy.ResultCallbackTemplate] (docker-java-stream-1954350275) Error during callback: com.github.dockerjava.api.exception.InternalServerErrorException: Status 500: {"message":"Head \"https://registry-1.docker.io/v2/testcontainers/ryuk/manifests/0.3.3\": unauthorized: incorrect username or password"}

        at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.execute(DefaultInvocationBuilder.java:247)
        at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.lambda$executeAndStream$1(DefaultInvocationBuilder.java:269)
        at java.base/java.lang.Thread.run(Thread.java:829)

2022-05-08 10:52:57,019 INFO  [io.qua.dep.dev.IsolatedDevModeMain] (main) Attempting to start live reload endpoint to recover from previous Quarkus startup failure
2022-05-08 10:52:57,037 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
        [error]: Build step io.quarkus.datasource.deployment.devservices.DevServicesDatasourceProcessor#launchDatabases threw an exception: java.lang.RuntimeException: com.github.dockerjava.api.exception.InternalServerErrorException: Status 500: {"message":"Head \"https://registry-1.docker.io/v2/testcontainers/ryuk/manifests/0.3.3\": unauthorized: incorrect username or password"}

        at io.quarkus.datasource.deployment.devservices.DevServicesDatasourceProcessor.startDevDb(DevServicesDatasourceProcessor.java:314)
        at io.quarkus.datasource.deployment.devservices.DevServicesDatasourceProcessor.launchDatabases(DevServicesDatasourceProcessor.java:121)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at io.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:882)
        at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
        at java.base/java.lang.Thread.run(Thread.java:829)
        at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: com.github.dockerjava.api.exception.InternalServerErrorException: Status 500: {"message":"Head \"https://registry-1.docker.io/v2/testcontainers/ryuk/manifests/0.3.3\": unauthorized: incorrect username or password"}

        at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.execute(DefaultInvocationBuilder.java:247)
        at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.lambda$executeAndStream$1(DefaultInvocationBuilder.java:269)
        at java.base/java.lang.Thread.run(Thread.java:829)
  • 爲了避免上述錯誤,以下兩種方式都可以,請您二選一即可
  1. 提前下載docker鏡像,命令是docker pull testcontainers/ryuk:0.3.3(當您看到此文是,tag可能不是0.3.3了,你可以從錯誤信息中確定您那邊的tag)
  2. 如果您有docker賬號,執行命令docker login index.docker.io登錄docker

dev這個profile的配置文件

  • 新增名文件application-dev.properties,裏面就一行內容
quarkus.hibernate-orm.sql-load-script=import.sql
  • 可見和之前的application-test.properties相比,dev這個profile下的配置文件中,不能有任何數據庫配置(數據庫IP、端口、庫名、賬號、密碼等)

啓動應用

  • 進入目錄quarkus-tutorials/basic-db,執行命令mvn quarkus:dev啓動應用,控制檯輸入如下
[INFO] Nothing to compile - all classes are up to date
Listening for transport dt_socket at address: 5005
2022-05-08 17:51:48,010 INFO  [io.qua.dat.dep.dev.DevServicesDatasourceProcessor] (build-12) Dev Services for the default datasource (postgresql) started.
2022-05-08 17:51:48,011 INFO  [io.qua.hib.orm.dep.HibernateOrmProcessor] (build-5) Setting quarkus.hibernate-orm.database.generation=drop-and-create to initialize Dev Services managed database
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2022-05-08 17:51:48,244 INFO  [io.agr.pool] (Quarkus Main Thread) Datasource '<default>': Initial size smaller than min. Connections will be created when necessary

Hibernate: 
    
    drop table if exists known_fruits cascade
2022-05-08 17:51:48,510 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) SQL Warning Code: 0, SQLState: 00000
2022-05-08 17:51:48,511 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) table "known_fruits" does not exist, skipping
Hibernate: 
    
    drop sequence if exists known_fruits_id_seq
2022-05-08 17:51:48,512 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) SQL Warning Code: 0, SQLState: 00000
2022-05-08 17:51:48,512 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) sequence "known_fruits_id_seq" does not exist, skipping
Hibernate: create sequence known_fruits_id_seq start 10 increment 1
Hibernate: 
    
    create table known_fruits (
       id int4 not null,
        name varchar(40),
        primary key (id)
    )

Hibernate: 
    
    alter table if exists known_fruits 
       add constraint UK_57g3m8wr3qxoj706a6hsqg6ye unique (name)

Hibernate: 
    INSERT INTO known_fruits(id, name) VALUES (1, 'Cherry')
Hibernate: 
    INSERT INTO known_fruits(id, name) VALUES (2, 'Apple')
Hibernate: 
    INSERT INTO known_fruits(id, name) VALUES (3, 'Banana')
2022-05-08 17:51:48,558 INFO  [io.quarkus] (Quarkus Main Thread) basic-db 1.0-SNAPSHOT on JVM (powered by Quarkus 2.7.3.Final) started in 2.706s. 
2022-05-08 17:51:48,559 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2022-05-08 17:51:48,559 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, hibernate-orm, jdbc-postgresql, narayana-jta, smallrye-context-propagation]
--
--
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
  • 從上述信息可見,即便是沒有數據庫,也沒有數據庫配置,quarkus也會通過docker爲應用把數據庫備好,讓應用順利啓動、連接、執行初始化SQL

執行單元測試

  • 從上述控制檯信息可見,目前的控制條已經處於命令行交互模式,先輸入o開啓測試日誌輸出開關
  • 然後再輸入r開始執行單元測試,控制檯輸出如下,可見和上一篇的操作並沒有什麼區別(還省去了數據庫的部署和配置)
image-20220508180422674
  • 至此,Zero Config Setup的體驗就完成了,雖然省去了數據庫的部署和配置,但profile被限定在dev,這怕是很多人不情願的,另外這都是後臺命令的操作,IDEA的單元測試頁面也不知道如何與quarkus的dev模式結合起來用,又是個巨大損失,所以,Zero Config Setup到底適不適用也是見仁見智

接受數據庫的license

  • 如果您用的數據庫是DB2或者MSSQL,在使用Zero Config Setup的時候會涉及到接受license的操作,您需要新增文件src/main/resources/container-license-acceptance.txt,內容如下,就是數據庫的鏡像名
ibmcom/db2:11.5.0.0a
mcr.microsoft.com/mssql/server:2017-CU12

MySQL的配置

  • 在使用MySQL的時候,我們可能對其做一些配置,那麼Zero Config Setup提供的MySQL就無法滿足我們的需求了,這裏可以通過配置來指定MySQL配置信息(個人的感覺,就是爲了解決一個問題而引入了新的問題)
quarkus.datasource.devservices.container-properties.TC_MY_CNF=testcontainers/mysql-conf

發現神祕信息

  • 接下來聊聊一次偶然的發現,既有驚喜也有疑惑,還希望親愛的讀者能夠給予指導和建議

  • 回想一下,當您使用mvn quarkus:dev啓動應用後,控制檯提示如下信息

Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
  • 於是,我按照上述提示輸入冒號,進入quarkus的終端模式,控制條提示如下
You are now in Quarkus Terminal. Your app is still running. Use `help` or tab completion to explore, `quit` or `q` to return to your application.
quarkus$
  • 然後,輸入postgres print-command,就會看到quarkus創建的數據庫信息,賬號、密碼、端口、庫名、啥都有,如下,真是神奇啊
quarkus$ postgres print-command
PGPASSWORD=quarkus psql --host=localhost --port=49294 --username=quarkus default
  • 上述信息,應該是quarkus在docker上創建的數據庫信息,於是我興沖沖地用IDEA的數據庫工具去連接這個數據庫,如下圖,天哪,連接成功了
image-20220508182514692
  • 然後查看錶的數據,如下圖,正是初始化腳本import.sql中新增的內容
image-20220508183042894
  • 本以爲發現了quarkus的驚天祕密,今後開發中隨時可以連接此數據庫查看數據,結果發現單元測試對數據的任何寫操作,都不會改變上圖表中的內容,這和使用自己的數據庫是完全不同的,上一篇文章中,咱們執行完單元測試後,寫操作的結果在數據庫中是可以查到的

  • 目前還沒有查到上述問題的原因,估計是quarkus自己內部的處理機制吧,例如自動rollback,或者某些程度的可見性隔離等,這都是猜的,親愛的讀者,如果您知道了原因,麻煩您在回覆中指點一二,謝謝了

  • 其實這也不是什麼問題,不去查那個表就行了,單元測試的讀寫功能是正常的,也就是說單元測試中,數據發生變化後程序可以讀取到變化後的數據,只是我們用工具看不到變化而已(官方文檔也沒有提及用工具去連接那個表,應該是不推薦這麼做)

  • 至此,quarkus的Zero Config Setup體驗完成,希望這個小技能可以對您有所幫助,以更簡單的操作度過編碼和自測的時光

歡迎關注博客園:程序員欣宸

學習路上,你不孤單,欣宸原創一路相伴...

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