### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 一個應用同時連接多個資料庫進行操作,這是 ...
歡迎訪問我的GitHub
這裡分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos
本篇概覽
- 一個應用同時連接多個資料庫進行操作,這是常見的場景,quarkus也不例外,今天就隨本文一起來實戰多數據源操作
- 如下圖,今天要創建名為multi-db-demo的應用,此應用同時連接兩個資料庫,名為fist-db的庫中是賣家表,名為second-db的庫中是買家表
- 為了簡化demo,本篇繼續堅持不支持web服務,用單元測試來驗證應用同時操作兩個資料庫沒有問題
限制
- quarkus連接和操作資料庫的方式有兩種:傳統JDBC和反應式(reactive),咱們前文演示的demo就是傳統JDBC方式
- 截止當前(最新版本是2.9),只有JDBC方式支持多數據源,反應式還不支持
準備工作
- 實戰前先把環境準備一下,既然是多數據源操作,那就要準備至少兩個資料庫了,請您將MySQL和PostgreSQL準備好再做下麵的數據準備工作
- 先在MySQL資料庫建庫建表,參考SQL如下
# 建資料庫
CREATE DATABASE first_db;
# 選中資料庫
use first_db;
# 建表
CREATE TABLE IF NOT EXISTS `seller`(
`id` INT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`product_num` INT NULL,
PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 新增三條記錄
insert into seller (name, product_num) values ('seller1', 1111);
insert into seller (name, product_num) values ('seller2', 2222);
insert into seller (name, product_num) values ('seller3', 3333);
- 然後是在PostgreSQL建庫建表,參考SQL如下
# 建資料庫
CREATE DATABASE second_db;
# 建表
CREATE TABLE buyer(
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
order_num int NOT NULL
);
# 新增兩條記錄
insert into buyer (name, order_num) values ('buyer1', 100);
insert into buyer (name, order_num) values ('buyer2', 200);
- 再整理一下兩個資料庫的地址,稍後用到
- MySQL:jdbc:mysql://192.168.50.43:3306/first_db
- PostgreSQL:jdbc:postgresql://192.168.50.43:15432/second_db
開發-創建子工程
- 《quarkus實戰之一:準備工作》已創建了父工程,今天在此父工程下新增名為multi-db-demo的子工程,其pom與前文的工程區別不大,新增MySQL庫,所有依賴如下
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<!-- JDBC庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-agroal</artifactId>
</dependency>
<!-- hibernate庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
<!-- postgresql庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<!-- mysql庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mysql</artifactId>
</dependency>
<!-- 單元測試庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
開發-配置文件
- 接下來就是多數據源操作最關鍵的地方了:配置文件,為了滿足多個profile的需要,這裡繼續使用application.properties和application-xxx.properties組合的方式,application.properties里存放公共配置,例如資料庫類型,而application-xxx.properties裡面是和各個profile環境有關的配置項,例如資料庫IP地址、賬號密碼等,如下圖
- 這裡再強調一下配置的內容:配置的是數據源(datasource),代碼中連接資料庫時用到的配置項
- 接下來就是配置項了,這裡有兩個數據源,所以這兩個數據源配置項都要有,咱們逐個配置
- 首先是first-db的,我們將其當做應用的預設數據源,那麼它的配置和原來單數據源的沒有任何卻別,如下所示
# first-db的配置,下麵五個配置項在application.properties文件中
quarkus.hibernate-orm.log.sql=true
quarkus.datasource.db-kind=mysql
quarkus.datasource.jdbc.max-size=8
quarkus.datasource.jdbc.min-size=2
quarkus.hibernate-orm.packages=com.bolingcavalry.multidb.entity.firstdb
# first-db的配置,下麵三個配置項在application-test.properties文件中,即test環境下fitst-db的資料庫地址、賬號、密碼等信息
quarkus.datasource.username=root
quarkus.datasource.password=123456
quarkus.datasource.jdbc.url=jdbc:mysql://192.168.50.43:3306/first_db
- 其次是second_db的配置,註意quarkus對非預設數據源配置的要求:配置項的key中都要有數據源名稱,下圖是預設數據源和非預設數據源配置項的對比,紅色內容是數據源名稱,放在第二個點號後面
- 按照上述規則,second_db的所有配置如下
# second_db的配置,下麵五個配置項在application.properties文件中
quarkus.hibernate-orm.second_db.log.sql=true
quarkus.datasource.second_db.db-kind=postgresql
quarkus.datasource.second_db.jdbc.max-size=8
quarkus.datasource.second_db.jdbc.min-size=2
quarkus.hibernate-orm.second_db.datasource=second_db
quarkus.hibernate-orm.second_db.packages=com.bolingcavalry.multidb.entity.seconddb
# second_db的配置,下麵三個配置項在application-test.properties文件中,即test環境下second_db的資料庫地址、賬號、密碼等信息
quarkus.datasource.second_db.username=quarkus
quarkus.datasource.second_db.password=123456
quarkus.datasource.second_db.jdbc.url=jdbc:postgresql://192.168.50.43:15432/second_db
-
還要註意一點:quarkus.hibernate-orm.packages和quarkus.hibernate-orm.second_db.packages分別代表預設數據源和second_db各自表的entity類所在package,稍後編碼寫entity類的時候,seller表的entity只能放在com.bolingcavalry.multidb.entity.firstdb,buyer表的entity類只能放在com.bolingcavalry.multidb.entity.seconddb
-
配置完成,可以開始寫代碼了
開發-編碼
-
先寫entity類,註意entity類的package要對應quarkus.hibernate-orm.packages或者quarkus.hibernate-orm.second_db.packages這兩個配置項的值
-
首先是first_db的賣家表seller的entity類,完整源碼如下,註意主鍵生成的註解GeneratedValue的配置
package com.bolingcavalry.multidb.entity.firstdb;
import javax.persistence.*;
@Entity
@Table(name = "seller")
@NamedQuery(name = "Seller.findAll", query = "SELECT f FROM Seller f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Cacheable
public class Seller {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String name;
@Column(name = "product_num")
private int productNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getProductNum() {
return productNum;
}
public void setProductNum(int productNum) {
this.productNum = productNum;
}
}
- 首先是second_db的買家表buyer的entity類,完整源碼如下,註意主鍵生成的註解GeneratedValue的配置
package com.bolingcavalry.multidb.entity.seconddb;
import javax.persistence.*;
@Entity
@Table(name = "buyer")
@NamedQuery(name = "Buyer.findAll", query = "SELECT f FROM Buyer f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Cacheable
public class Buyer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String name;
@Column(name = "order_num")
private int orderNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrderNum() {
return orderNum;
}
public void setOrderNum(int orderNum) {
this.orderNum = orderNum;
}
}
-
可見除了package要和配置項的指定值對齊,上述兩個entity類並無任何特殊之處,不論單數據源還是多數據源,都是同樣的寫法
-
接下來是服務類了,先看賣家表對應的服務類SellerService.java,如下,由於seller表對應的資料庫是當前應用的預設資料庫,所以在操作資料庫的時候,無需任何與數據源有關的特別設置,這和單數據源的應用是一樣的
@ApplicationScoped
public class SellerService {
@Inject
EntityManager entityManager;
public List<Seller> get() {
return entityManager.createNamedQuery("Seller.findAll", Seller.class)
.getResultList();
}
public Seller getSingle(Integer id) {
return entityManager.find(Seller.class, id);
}
@Transactional
public void create(Seller seller) {
entityManager.persist(seller);
}
@Transactional
public void update(Integer id, Seller seller) {
Seller entity = entityManager.find(Seller.class, id);
if (null!=entity) {
entity.setName(seller.getName());
}
}
@Transactional
public void delete(Integer id) {
Seller entity = entityManager.getReference(Seller.class, id);
if (null!=entity) {
entityManager.remove(entity);
}
}
}
- 然後是買家表buyer相關操作的服務類BuyerService.java,可見它的成員變數entityManager多了個註解PersistenceUnit,值等於配置文件中的資料庫名second_db,這個註解確保了entityManager用的是second_db的數據源,其他代碼和單數據源的操作並無區別
package com.bolingcavalry.multidb.service;
import com.bolingcavalry.multidb.entity.seconddb.Buyer;
import io.quarkus.hibernate.orm.PersistenceUnit;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.List;
@ApplicationScoped
public class BuyerService {
@Inject
@PersistenceUnit("second_db")
EntityManager entityManager;
public List<Buyer> get() {
return entityManager.createNamedQuery("Buyer.findAll", Buyer.class)
.getResultList();
}
public Buyer getSingle(Integer id) {
return entityManager.find(Buyer.class, id);
}
@Transactional
public void create(Buyer buyer) {
entityManager.persist(buyer);
}
@Transactional
public void update(Integer id, Buyer buyer) {
Buyer entity = entityManager.find(Buyer.class, id);
if (null!=entity) {
entity.setName(buyer.getName());
}
}
@Transactional
public void delete(Integer id) {
Buyer entity = entityManager.getReference(Buyer.class, id);
if (null!=entity) {
entityManager.remove(entity);
}
}
}
-
有個要格外註意的地方:PersistenceUnit類的package是io.quarkus.hibernate.orm,在import的時候要註意
-
代碼寫完了,接下來進入驗證環節,依然使用單元測試來驗證
開發-單元測試
- 雖然有兩個服務類(SellerService和BuyerService),但是單元測試類只有一個,這裡是為了模擬實際應用中同時操作兩個資料庫的場景,您也可以根據自身情況改成每個服務類一個單元測試類
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MultiDBTest {
/**
* first_db的seller表中,初始記錄數
*/
private static final int FIRST_DB_EXIST_RECORDS_SIZE = 3;
/**
* second_db的buyer表中,初始記錄數
*/
private static final int SECOND_DB_EXIST_RECORDS_SIZE = 2;
/**
* import.sql中,第一條記錄的id
*/
private static final int EXIST_FIRST_ID = 1;
/**
* 在Fruit.java中,id欄位的SequenceGenerator指定了initialValue等於10,
* 表示自增ID從10開始
*/
private static final int ID_SEQUENCE_INIT_VALUE = 10;
@Inject
SellerService sellerService;
@Inject
BuyerService buyerService;
@Test
@DisplayName("list")
@Order(1)
public void testGet() {
List<Seller> sellerList = sellerService.get();
// 判定非空
Assertions.assertNotNull(sellerList);
// seller表初始化時新增了3條記錄
Assertions.assertEquals(FIRST_DB_EXIST_RECORDS_SIZE, sellerList.size());
List<Buyer> buyerList = buyerService.get();
// 判定非空
Assertions.assertNotNull(buyerList);
// buyer表初始化時新增了2條記錄
Assertions.assertEquals(SECOND_DB_EXIST_RECORDS_SIZE, buyerList.size());
}
@Test
@DisplayName("getSingle")
@Order(2)
public void testGetSingle() {
// 用第二條記錄吧,第一條在執行testUpdate方法時被更改了
Seller seller = sellerService.getSingle(EXIST_FIRST_ID+1);
// 判定非空
Assertions.assertNotNull(seller);
// buyer表的第一條記錄
Assertions.assertEquals("seller2", seller.getName());
// 用第二條記錄吧,第一條在執行testUpdate方法時被更改了
Buyer buyer = buyerService.getSingle(EXIST_FIRST_ID+1);
// 判定非空
Assertions.assertNotNull(buyer);
// buyer表的第二條記錄
Assertions.assertEquals("buyer2", buyer.getName());
}
@Test
@DisplayName("update")
@Order(3)
public void testUpdate() {
// 驗證first_db的操作
String newName = LocalDateTime.now().toString();
Seller seller = new Seller();
seller.setName(newName);
// 更新資料庫
sellerService.update(EXIST_FIRST_ID, seller);
Seller sellerFromDB = sellerService.getSingle(EXIST_FIRST_ID);
// 從資料庫取出的對象,其名稱應該等於修改的名稱
Assertions.assertEquals(newName, sellerFromDB.getName());
// 驗證second_db的操作
Buyer buyer = new Buyer();
buyer.setName(newName);
// 更新資料庫
buyerService.update(EXIST_FIRST_ID, buyer);
Buyer buyerFromDB = buyerService.getSingle(EXIST_FIRST_ID);
// 從資料庫取出的對象,其名稱應該等於修改的名稱
Assertions.assertEquals(newName, buyerFromDB.getName());
}
@Test
@DisplayName("create")
@Order(3)
public void testCreate() {
Seller seller = new Seller();
seller.setName("seller4");
sellerService.create(seller);
// 創建成功後,記錄主鍵肯定是大於3的
Assertions.assertTrue(seller.getId()>FIRST_DB_EXIST_RECORDS_SIZE);
// 記錄總數應該等於已有記錄數+1
Assertions.assertEquals(FIRST_DB_EXIST_RECORDS_SIZE+1, sellerService.get().size());
Buyer buyer = new Buyer();
buyer.setName("buyer3");
buyerService.create(buyer);
// 創建成功後,記錄主鍵肯定是大於3的
Assertions.assertTrue(buyer.getId()>SECOND_DB_EXIST_RECORDS_SIZE);
// 記錄總數應該等於已有記錄數+1
Assertions.assertEquals(SECOND_DB_EXIST_RECORDS_SIZE+1, buyerService.get().size());
}
@Test
@DisplayName("delete")
@Order(5)
public void testDelete() {
List<Seller> sellers = sellerService.get();
// 先記刪除前的總數
int numBeforeDelete = sellers.size();
// 刪除最後一條記錄
sellerService.delete(sellers.get(numBeforeDelete-1).getId());
// 記錄數應該應該等於刪除前的數量減一
Assertions.assertEquals(numBeforeDelete-1, sellerService.get().size());
List<Buyer> buyers = buyerService.get();
// 先記刪除前的總數
numBeforeDelete = buyers.size();
// 刪除最後一條記錄
buyerService.delete(buyers.get(numBeforeDelete-1).getId());
// 記錄數應該應該等於刪除前的數量減一
Assertions.assertEquals(numBeforeDelete-1, buyerService.get().size());
}
}
- 代碼中已經有詳細的註釋,就不多贅述了
驗證
- 請再次確認資料庫、表、記錄都已經準備就緒
- 運行單元測試類,如下圖,一切符合預期
- 去資料庫看一下,如下圖紅框所示,那是執行testUpdate方法時更新的結果
- 至此,quarkus連接多個資料庫的實戰操作已完成,希望這個實用技能可以給您一些參考
源碼下載
- 本篇實戰的完整源碼可在GitHub下載到,地址和鏈接信息如下表所示(https://github.com/zq2599/blog_demos)
名稱 | 鏈接 | 備註 |
---|---|---|
項目主頁 | 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文件夾下,如下圖紅框
- quarkus-tutorials是個父工程,裡面有多個module,本篇實戰的module是multi-db-demo,如下圖紅框
本篇概覽
- 一個應用同時連接多個資料庫進行操作,這是常見的場景,quarkus也不例外,今天就隨本文一起來實戰多數據源操作
- 如下圖,今天要創建名為multi-db-demo的應用,此應用同時連接兩個資料庫,名為fist-db的庫中是賣家表,名為second-db的庫中是買家表
- 為了簡化demo,本篇繼續堅持不支持web服務,用單元測試來驗證應用同時操作兩個資料庫沒有問題
限制
- quarkus連接和操作資料庫的方式有兩種:傳統JDBC和反應式(reactive),咱們前文演示的demo就是傳統JDBC方式
- 截止當前(最新版本是2.9),只有JDBC方式支持多數據源,反應式還不支持
準備工作
- 實戰前先把環境準備一下,既然是多數據源操作,那就要準備至少兩個資料庫了,請您將MySQL和PostgreSQL準備好再做下麵的數據準備工作
- 先在MySQL資料庫建庫建表,參考SQL如下
# 建資料庫
CREATE DATABASE first_db;
# 選中資料庫
use first_db;
# 建表
CREATE TABLE IF NOT EXISTS `seller`(
`id` INT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`product_num` INT NULL,
PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 新增三條記錄
insert into seller (name, product_num) values ('seller1', 1111);
insert into seller (name, product_num) values ('seller2', 2222);
insert into seller (name, product_num) values ('seller3', 3333);
- 然後是在PostgreSQL建庫建表,參考SQL如下
# 建資料庫
CREATE DATABASE second_db;
# 建表
CREATE TABLE buyer(
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
order_num int NOT NULL
);
# 新增兩條記錄
insert into buyer (name, order_num) values ('buyer1', 100);
insert into buyer (name, order_num) values ('buyer2', 200);
- 再整理一下兩個資料庫的地址,稍後用到
- MySQL:jdbc:mysql://192.168.50.43:3306/first_db
- PostgreSQL:jdbc:postgresql://192.168.50.43:15432/second_db
開發-創建子工程
- 《quarkus實戰之一:準備工作》已創建了父工程,今天在此父工程下新增名為multi-db-demo的子工程,其pom與前文的工程區別不大,新增MySQL庫,所有依賴如下
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<!-- JDBC庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-agroal</artifactId>
</dependency>
<!-- hibernate庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
<!-- postgresql庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<!-- mysql庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mysql</artifactId>
</dependency>
<!-- 單元測試庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
開發-配置文件
- 接下來就是多數據源操作最關鍵的地方了:配置文件,為了滿足多個profile的需要,這裡繼續使用application.properties和application-xxx.properties組合的方式,application.properties里存放公共配置,例如資料庫類型,而application-xxx.properties裡面是和各個profile環境有關的配置項,例如資料庫IP地址、賬號密碼等,如下圖
- 這裡再強調一下配置的內容:配置的是數據源(datasource),代碼中連接資料庫時用到的配置項
- 接下來就是配置項了,這裡有兩個數據源,所以這兩個數據源配置項都要有,咱們逐個配置
- 首先是first-db的,我們將其當做應用的預設數據源,那麼它的配置和原來單數據源的沒有任何卻別,如下所示
# first-db的配置,下麵五個配置項在application.properties文件中
quarkus.hibernate-orm.log.sql=true
quarkus.datasource.db-kind=mysql
quarkus.datasource.jdbc.max-size=8
quarkus.datasource.jdbc.min-size=2
quarkus.hibernate-orm.packages=com.bolingcavalry.multidb.entity.firstdb
# first-db的配置,下麵三個配置項在application-test.properties文件中,即test環境下fitst-db的資料庫地址、賬號、密碼等信息
quarkus.datasource.username=root
quarkus.datasource.password=123456
quarkus.datasource.jdbc.url=jdbc:mysql://192.168.50.43:3306/first_db
- 其次是second_db的配置,註意quarkus對非預設數據源配置的要求:配置項的key中都要有數據源名稱,下圖是預設數據源和非預設數據源配置項的對比,紅色內容是數據源名稱,放在第二個點號後面
- 按照上述規則,second_db的所有配置如下
# second_db的配置,下麵五個配置項在application.properties文件中
quarkus.hibernate-orm.second_db.log.sql=true
quarkus.datasource.second_db.db-kind=postgresql
quarkus.datasource.second_db.jdbc.max-size=8
quarkus.datasource.second_db.jdbc.min-size=2
quarkus.hibernate-orm.second_db.datasource=second_db
quarkus.hibernate-orm.second_db.packages=com.bolingcavalry.multidb.entity.seconddb
# second_db的配置,下麵三個配置項在application-test.properties文件中,即test環境下second_db的資料庫地址、賬號、密碼等信息
quarkus.datasource.second_db.username=quarkus
quarkus.datasource.second_db.password=123456
quarkus.datasource.second_db.jdbc.url=jdbc:postgresql://192.168.50.43:15432/second_db
-
還要註意一點:quarkus.hibernate-orm.packages和quarkus.hibernate-orm.second_db.packages分別代表預設數據源和second_db各自表的entity類所在package,稍後編碼寫entity類的時候,seller表的entity只能放在com.bolingcavalry.multidb.entity.firstdb,buyer表的entity類只能放在com.bolingcavalry.multidb.entity.seconddb
-
配置完成,可以開始寫代碼了
開發:編碼
-
先寫entity類,註意entity類的package要對應quarkus.hibernate-orm.packages或者quarkus.hibernate-orm.second_db.packages這兩個配置項的值
-
首先是first_db的賣家表seller的entity類,完整源碼如下,註意主鍵生成的註解GeneratedValue的配置
package com.bolingcavalry.multidb.entity.firstdb;
import javax.persistence.*;
@Entity
@Table(name = "seller")
@NamedQuery(name = "Seller.findAll", query = "SELECT f FROM Seller f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Cacheable
public class Seller {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String name;
@Column(name = "product_num")
private int productNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getProductNum() {
return productNum;
}
public void setProductNum(int productNum) {
this.productNum = productNum;
}
}
- 首先是second_db的買家表buyer的entity類,完整源碼如下,註意主鍵生成的註解GeneratedValue的配置
package com.bolingcavalry.multidb.entity.seconddb;
import javax.persistence.*;
@Entity
@Table(name = "buyer")
@NamedQuery(name = "Buyer.findAll", query = "SELECT f FROM Buyer f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Cacheable
public class Buyer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String name;
@Column(name = "order_num")
private int orderNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrderNum() {
return orderNum;
}
public void setOrderNum(int orderNum) {
this.orderNum = orderNum;
}
}
-
可見除了package要和配置項的指定值對齊,上述兩個entity類並無任何特殊之處,不論單數據源還是多數據源,都是同樣的寫法
-
接下來是服務類了,先看賣家表對應的服務類SellerService.java,如下,由於seller表對應的資料庫是當前應用的預設資料庫,所以在操作資料庫的時候,無需任何與數據源有關的特別設置,這和單數據源的應用是一樣的
@ApplicationScoped
public class SellerService {
@Inject
EntityManager entityManager;
public List<Seller> get() {
return entityManager.createNamedQuery("Seller.findAll", Seller.class)
.getResultList();
}
public Seller getSingle(Integer id) {
return entityManager.find(Seller.class, id);
}
@Transactional
public void create(Seller seller) {
entityManager.persist(seller);
}
@Transactional
public void update(Integer id, Seller seller) {
Seller entity = entityManager.find(Seller.class, id);
if (null!=entity) {
entity.setName(seller.getName());
}
}
@Transactional
public void delete(Integer id) {
Seller entity = entityManager.getReference(Seller.class, id);
if (null!=entity) {
entityManager.remove(entity);
}
}
}
- 然後是買家表buyer相關操作的服務類BuyerService.java,可見它的成員變數entityManager多了個註解PersistenceUnit,值等於配置文件中的資料庫名second_db,這個註解確保了entityManager用的是second_db的數據源,其他代碼和單數據源的操作並無區別
package com.bolingcavalry.multidb.service;
import com.bolingcavalry.multidb.entity.seconddb.Buyer;
import io.quarkus.hibernate.orm.PersistenceUnit;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.List;
@ApplicationScoped
public class BuyerService {
@Inject
@PersistenceUnit("second_db")
EntityManager entityManager;
public List<Buyer> get() {
return entityManager.createNamedQuery("Buyer.findAll", Buyer.class)
.getResultList();
}
public Buyer getSingle(Integer id) {
return entityManager.find(Buyer.class, id);
}
@Transactional
public void create(Buyer buyer) {
entityManager.persist(buyer);
}
@Transactional
public void update(Integer id, Buyer buyer) {
Buyer entity = entityManager.find(Buyer.class, id);
if (null!=entity) {
entity.setName(buyer.getName());
}
}
@Transactional
public void delete(Integer id) {
Buyer entity = entityManager.getReference(Buyer.class, id);
if (null!=entity) {
entityManager.remove(entity);
}
}
}
-
有個要格外註意的地方:PersistenceUnit類的package是io.quarkus.hibernate.orm,在import的時候要註意
-
代碼寫完了,接下來進入驗證環節,依然使用單元測試來驗證
開發-單元測試
- 雖然有兩個服務類(SellerService和BuyerService),但是單元測試類只有一個,這裡是為了模擬實際應用中同時操作兩個資料庫的場景,您也可以根據自身情況改成每個服務類一個單元測試類
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MultiDBTest {
/**
* first_db的seller表中,初始記錄數
*/
private static final int FIRST_DB_EXIST_RECORDS_SIZE = 3;
/**
* second_db的buyer表中,初始記錄數
*/
private static final int SECOND_DB_EXIST_RECORDS_SIZE = 2;
/**
* import.sql中,第一條記錄的id
*/
private static final int EXIST_FIRST_ID = 1;
/**
* 在Fruit.java中,id欄位的SequenceGenerator指定了initialValue等於10,
* 表示自增ID從10開始
*/
private static final int ID_SEQUENCE_INIT_VALUE = 10;
@Inject
SellerService sellerService;
@Inject
BuyerService buyerService;
@Test
@DisplayName("list")
@Order(1)
public void testGet() {
List<Seller> sellerList = sellerService.get();
// 判定非空
Assertions.assertNotNull(sellerList);
// seller表初始化時新增了3條記錄
Assertions.assertEquals(FIRST_DB_EXIST_RECORDS_SIZE, sellerList.size());
List<Buyer> buyerList = buyerService.get();
// 判定非空
Assertions.assertNotNull(buyerList);
// buyer表初始化時新增了2條記錄
Assertions.assertEquals(SECOND_DB_EXIST_RECORDS_SIZE, buyerList.size());
}
@Test
@DisplayName("getSingle")
@Order(2)
public void testGetSingle() {
// 用第二條記錄吧,第一條在執行testUpdate方法時被更改了
Seller seller = sellerService.getSingle(EXIST_FIRST_ID+1);
// 判定非空
Assertions.assertNotNull(seller);
// buyer表的第一條記錄
Assertions.assertEquals("seller2", seller.getName());
// 用第二條記錄吧,第一條在執行testUpdate方法時被更改了
Buyer buyer = buyerService.getSingle(EXIST_FIRST_ID+1);
// 判定非空
Assertions.assertNotNull(buyer);
// buyer表的第二條記錄
Assertions.assertEquals("buyer2", buyer.getName());
}
@Test
@DisplayName("update")
@Order(3)
public void testUpdate() {
// 驗證first_db的操作
String newName = LocalDateTime.now().toString();
Seller seller = new Seller();
seller.setName(newName);
// 更新資料庫
sellerService.update(EXIST_FIRST_ID, seller);
Seller sellerFromDB = sellerService.getSingle(EXIST_FIRST_ID);
// 從資料庫取出的對象,其名稱應該等於修改的名稱
Assertions.assertEquals(newName, sellerFromDB.getName());
// 驗證second_db的操作
Buyer buyer = new Buyer();
buyer.setName(newName);
// 更新資料庫
buyerService.update(EXIST_FIRST_ID, buyer);
Buyer buyerFromDB = buyerService.getSingle(EXIST_FIRST_ID);
// 從資料庫取出的對象,其名稱應該等於修改的名稱
Assertions.assertEquals(newName, buyerFromDB.getName());
}
@Test
@DisplayName("create")
@Order(3)
public void testCreate() {
Seller seller = new Seller();
seller.setName("seller4");
sellerService.create(seller);
// 創建成功後,記錄主鍵肯定是大於3的
Assertions.assertTrue(seller.getId()>FIRST_DB_EXIST_RECORDS_SIZE);
// 記錄總數應該等於已有記錄數+1
Assertions.assertEquals(FIRST_DB_EXIST_RECORDS_SIZE+1, sellerService.get().size());
Buyer buyer = new Buyer();
buyer.setName("buyer3");
buyerService.create(buyer);
// 創建成功後,記錄主鍵肯定是大於3的
Assertions.assertTrue(buyer.getId()>SECOND_DB_EXIST_RECORDS_SIZE);
// 記錄總數應該等於已有記錄數+1
Assertions.assertEquals(SECOND_DB_EXIST_RECORDS_SIZE+1, buyerService.get().size());
}
@Test
@DisplayName("delete")
@Order(5)
public void testDelete() {
List<Seller> sellers = sellerService.get();
// 先記刪除前的總數
int numBeforeDelete = sellers.size();
// 刪除最後一條記錄
sellerService.delete(sellers.get(numBeforeDelete-1).getId());
// 記錄數應該應該等於刪除前的數量減一
Assertions.assertEquals(numBeforeDelete-1, sellerService.get().size());
List<Buyer> buyers = buyerService.get();
// 先記刪除前的總數
numBeforeDelete = buyers.size();
// 刪除最後一條記錄
buyerService.delete(buyers.get(numBeforeDelete-1).getId());
// 記錄數應該應該等於刪除前的數量減一
Assertions.assertEquals(numBeforeDelete-1, buyerService.get().size());
}
}
- 代碼中已經有詳細的註釋,就不多贅述了
驗證
- 請再次確認資料庫、表、記錄都已經準備就緒
- 運行單元測試類,如下圖,一切符合預期
- 去資料庫看一下,如下圖紅框所示,那是執行testUpdate方法時更新的結果
- 至此,quarkus連接多個資料庫的實戰操作已完成,希望這個實用技能可以給您一些參考
源碼下載
- 本篇實戰的完整源碼可在GitHub下載到,地址和鏈接信息如下表所示(https://github.com/zq2599/blog_demos)
名稱 | 鏈接 | 備註 |
---|---|---|
項目主頁 | 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文件夾下,如下圖紅框
- quarkus-tutorials是個父工程,裡面有多個module,本篇實戰的module是multi-db-demo,如下圖紅框
本篇概覽
- 一個應用同時連接多個資料庫進行操作,這是常見的場景,quarkus也不例外,今天就隨本文一起來實戰多數據源操作
- 如下圖,今天要創建名為multi-db-demo的應用,此應用同時連接兩個資料庫,名為fist-db的庫中是賣家表,名為second-db的庫中是買家表
- 為了簡化demo,本篇繼續堅持不支持web服務,用單元測試來驗證應用同時操作兩個資料庫沒有問題
限制
- quarkus連接和操作資料庫的方式有兩種:傳統JDBC和反應式(reactive),咱們前文演示的demo就是傳統JDBC方式
- 截止當前(最新版本是2.9),只有JDBC方式支持多數據源,反應式還不支持
準備工作
- 實戰前先把環境準備一下,既然是多數據源操作,那就要準備至少兩個資料庫了,請您將MySQL和PostgreSQL準備好再做下麵的數據準備工作
- 先在MySQL資料庫建庫建表,參考SQL如下
# 建資料庫
CREATE DATABASE first_db;
# 選中資料庫
use first_db;
# 建表
CREATE TABLE IF NOT EXISTS `seller`(
`id` INT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`product_num` INT NULL,
PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 新增三條記錄
insert into seller (name, product_num) values ('seller1', 1111);
insert into seller (name, product_num) values ('seller2', 2222);
insert into seller (name, product_num) values ('seller3', 3333);
- 然後是在PostgreSQL建庫建表,參考SQL如下
# 建資料庫
CREATE DATABASE second_db;
# 建表
CREATE TABLE buyer(
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
order_num int NOT NULL
);
# 新增兩條記錄
insert into buyer (name, order_num) values ('buyer1', 100);
insert into buyer (name, order_num) values ('buyer2', 200);
- 再整理一下兩個資料庫的地址,稍後用到
- MySQL:jdbc:mysql://192.168.50.43:3306/first_db
- PostgreSQL:jdbc:postgresql://192.168.50.43:15432/second_db
開發-創建子工程
- 《quarkus實戰之一:準備工作》已創建了父工程,今天在此父工程下新增名為multi-db-demo的子工程,其pom與前文的工程區別不大,新增MySQL庫,所有依賴如下
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<!-- JDBC庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-agroal</artifactId>
</dependency>
<!-- hibernate庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
<!-- postgresql庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<!-- mysql庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mysql</artifactId>
</dependency>
<!-- 單元測試庫 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
開發-配置文件
- 接下來就是多數據源操作最關鍵的地方了:配置文件,為了滿足多個profile的需要,這裡繼續使用application.properties和application-xxx.properties組合的方式,application.properties里存放公共配置,例如資料庫類型,而application-xxx.properties裡面是和各個profile環境有關的配置項,例如資料庫IP地址、賬號密碼等,如下圖
- 這裡再強調一下配置的內容:配置的是數據源(datasource),代碼中連接資料庫時用到的配置項
- 接下來就是配置項了,這裡有兩個數據源,所以這兩個數據源配置項都要有,咱們逐個配置
- 首先是first-db的,我們將其當做應用的預設數據源,那麼它的配置和原來單數據源的沒有任何卻別,如下所示
# first-db的配置,下麵五個配置項在application.properties文件中
quarkus.hibernate-orm.log.sql=true
quarkus.datasource.db-kind=mysql
quarkus.datasource.jdbc.max-size=8
quarkus.datasource.jdbc.min-size=2
quarkus.hibernate-orm.packages=com.bolingcavalry.multidb.entity.firstdb
# first-db的配置,下麵三個配置項在application-test.properties文件中,即test環境下fitst-db的資料庫地址、賬號、密碼等信息
quarkus.datasource.username=root
quarkus.datasource.password=123456
quarkus.datasource.jdbc.url=jdbc:mysql://192.168.50.43:3306/first_db
- 其次是second_db的配置,註意quarkus對非預設數據源配置的要求:配置項的key中都要有數據源名稱,下圖是預設數據源和非預設數據源配置項的對比,紅色內容是數據源名稱,放在第二個點號後面
- 按照上述規則,second_db的所有配置如下
# second_db的配置,下麵五個配置項在application.properties文件中
quarkus.hibernate-orm.second_db.log.sql=true
quarkus.datasource.second_db.db-kind=postgresql
quarkus.datasource.second_db.jdbc.max-size=8
quarkus.datasource.second_db.jdbc.min-size=2
quarkus.hibernate-orm.second_db.datasource=second_db
quarkus.hibernate-orm.second_db.packages=com.bolingcavalry.multidb.entity.seconddb
# second_db的配置,下麵三個配置項在application-test.properties文件中,即test環境下second_db的資料庫地址、賬號、密碼等信息
quarkus.datasource.second_db.username=quarkus
quarkus.datasource.second_db.password=123456
quarkus.datasource.second_db.jdbc.url=jdbc:postgresql://192.168.50.43:15432/second_db
-
還要註意一點:quarkus.hibernate-orm.packages和quarkus.hibernate-orm.second_db.packages分別代表預設數據源和second_db各自表的entity類所在package,稍後編碼寫entity類的時候,seller表的entity只能放在com.bolingcavalry.multidb.entity.firstdb,buyer表的entity類只能放在com.bolingcavalry.multidb.entity.seconddb
-
配置完成,可以開始寫代碼了
開發:編碼
-
先寫entity類,註意entity類的package要對應quarkus.hibernate-orm.packages或者quarkus.hibernate-orm.second_db.packages這兩個配置項的值
-
首先是first_db的賣家表seller的entity類,完整源碼如下,註意主鍵生成的註解GeneratedValue的配置
package com.bolingcavalry.multidb.entity.firstdb;
import javax.persistence.*;
@Entity
@Table(name = "seller")
@NamedQuery(name = "Seller.findAll", query = "SELECT f FROM Seller f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Cacheable
public class Seller {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String name;
@Column(name = "product_num")
private int productNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getProductNum() {
return productNum;
}
public void setProductNum(int productNum) {
this.productNum = productNum;
}
}
- 首先是second_db的買家表buyer的entity類,完整源碼如下,註意主鍵生成的註解GeneratedValue的配置
package com.bolingcavalry.multidb.entity.seconddb;
import javax.persistence.*;
@Entity
@Table(name = "buyer")
@NamedQuery(name = "Buyer.findAll", query = "SELECT f FROM Buyer f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Cacheable
public class Buyer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String name;
@Column(name = "order_num")
private int orderNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrderNum() {
return orderNum;
}
public void setOrderNum(int orderNum) {
this.orderNum = orderNum;
}
}
-
可見除了package要和配置項的指定值對齊,上述兩個entity類並無任何特殊之處,不論單數據源還是多數據源,都是同樣的寫法
-
接下來是服務類了,先看賣家表對應的服務類SellerService.java,如下,由於seller表對應的資料庫是當前應用的預設資料庫,所以在操作資料庫的時候,無需任何與數據源有關的特別設置,這和單數據源的應用是一樣的
@ApplicationScoped
public class SellerService {
@Inject
EntityManager entityManager;
public List<Seller> get() {
return entityManager.createNamedQuery("Seller.findAll", Seller.class)
.getResultList();
}
public Seller getSingle(Integer id) {
return entityManager.find(Seller.class, id);
}
@Transactional
public void create(Seller seller) {
entityManager.persist(seller);
}
@Transactional
public void update(Integer id, Seller seller) {
Seller entity = entityManager.find(Seller.class, id);
if (null!=entity) {
entity.setName(seller.getName());
}
}
@Transactional
public void delete(Integer id) {
Seller entity = entityManager.getReference(Seller.class, id);
if (null!=entity) {
entityManager.remove(entity);
}
}
}
- 然後是買家表buyer相關操作的服務類BuyerService.java,可見它的成員變數entityManager多了個註解PersistenceUnit,值等於配置文件中的資料庫名second_db,這個註解確保了entityManager用的是second_db的數據源,其他代碼和單數據源的操作並無區別
package com.bolingcavalry.multidb.service;
import com.bolingcavalry.multidb.entity.seconddb.Buyer;
import io.quarkus.hibernate.orm.PersistenceUnit;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.List;
@ApplicationScoped
public class BuyerService {
@Inject
@PersistenceUnit("second_db")
EntityManager entityManager;
public List<Buyer> get() {
return entityManager.createNamedQuery("Buyer.findAll", Buyer.class)
.getResultList();
}
public Buyer getSingle(Integer id) {
return entityManager.find(Buyer.class, id);
}
@Transactional
public void create(Buyer buyer) {
entityManager.persist(buyer);
}
@Transactional
public void update(Integer id, Buyer buyer) {
Buyer entity = entityManager.find(Buyer.class, id);
if (null!=entity) {
entity.setName(buyer.getName());
}
}
@Transactional
public void delete(Integer id) {
Buyer entity = entityManager.getReference(Buyer.class, id);
if (null!=entity) {
entityManager.remove(entity);
}
}
}
-
有個要格外註意的地方:PersistenceUnit類的package是io.quarkus.hibernate.orm,在import的時候要註意
-
代碼寫完了,接下來進入驗證環節,依然使用單元測試來驗證
開發-單元測試
- 雖然有兩個服務類(SellerService和BuyerService),但是單元測試類只有一個,這裡是為了模擬實際應用中同時操作兩個資料庫的場景,您也可以根據自身情況改成每個服務類一個單元測試類
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MultiDBTest {
/**
* first_db的seller表中,初始記錄數
*/
private static final int FIRST_DB_EXIST_RECORDS_SIZE = 3;
/**
* second_db的buyer表中,初始記錄數
*/
private static final int SECOND_DB_EXIST_RECORDS_SIZE = 2;
/**
* import.sql中,第一條記錄的id
*/
private static final int EXIST_FIRST_ID = 1;
/**
* 在Fruit.java中,id欄位的SequenceGenerator指定了initialValue等於10,
* 表示自增ID從10開始
*/
private static final int ID_SEQUENCE_INIT_VALUE = 10;
@Inject
SellerService sellerService;
@Inject
BuyerService buyerService;
@Test
@DisplayName("list")
@Order(1)
public void testGet() {
List<Seller> sellerList = sellerService.get();
// 判定非空
Assertions.assertNotNull(sellerList);
// seller表初始化時新增了3條記錄
Assertions.assertEquals(FIRST_DB_EXIST_RECORDS_SIZE, sellerList.size());
List<Buyer> buyerList = buyerService.get();
// 判定非空
Assertions.assertNotNull(buyerList);
// buyer表初始化時新增了2條記錄
Assertions.assertEquals(SECOND_DB_EXIST_RECORDS_SIZE, buyerList.size());
}
@Test
@DisplayName("getSingle")
@Order(2)
public void testGetSingle() {
// 用第二條記錄吧,第一條在執行testUpdate方法時被更改了
Seller seller = sellerService.getSingle(EXIST_FIRST_ID+1);
// 判定非空
Assertions.assertNotNull(seller);
// buyer表的第一條記錄
Assertions.assertEquals("seller2", seller.getName());
// 用第二條記錄吧,第一條在執行testUpdate方法時被更改了
Buyer buyer = buyerService.getSingle(EXIST_FIRST_ID+1);
// 判定非空
Assertions.assertNotNull(buyer);
// buyer表的第二條記錄
Assertions.assertEquals("buyer2", buyer.getName());
}
@Test
@DisplayName("update")
@Order(3)
public void testUpdate() {
// 驗證first_db的操作
String newName = LocalDateTime.now().toString();
Seller seller = new Seller();
seller.setName(newName);
// 更新資料庫
sellerService.update(EXIST_FIRST_ID, seller);
Seller sellerFromDB = sellerService.getSingle(EXIST_FIRST_ID);
// 從資料庫取出的對象,其名稱應該等於修改的名稱
Assertions.assertEquals(newName, sellerFromDB.getName());
// 驗證second_db的操作
Buyer buyer = new Buyer();
buyer.setName(newName);
// 更新資料庫
buyerService.update(EXIST_FIRST_ID, buyer);
Buyer buyerFromDB = buyerService.getSingle(EXIST_FIRST_ID);
// 從資料庫取出的對象,其名稱應該等於修改的名稱
Assertions.assertEquals(newName, buyerFromDB.getName());
}
@Test
@DisplayName("create")
@Order(3)
public void testCreate() {
Seller seller = new Seller();
seller.setName("seller4");
sellerService.create(seller);
// 創建成功後,記錄主鍵肯定是大於3的
Assertions.assertTrue(seller.getId()>FIRST_DB_EXIST_RECORDS_SIZE);
// 記錄總數應該等於已有記錄數+1
Assertions.assertEquals(FIRST_DB_EXIST_RECORDS_SIZE+1, sellerService.get().size());
Buyer buyer = new Buyer();
buyer.setName("buyer3");
buyerService.create(buyer);
// 創建成功後,記錄主鍵肯定是大於3的
Assertions.assertTrue(buyer.getId()>SECOND_DB_EXIST_RECORDS_SIZE);
// 記錄總數應該等於已有記錄數+1
Assertions.assertEquals(SECOND_DB_EXIST_RECORDS_SIZE+1, buyerService.get().size());
}
@Test
@DisplayName("delete")
@Order(5)
public void testDelete() {
List<Seller> sellers = sellerService.get();
// 先記刪除前的總數
int numBeforeDelete = sellers.size();
// 刪除最後一條記錄
sellerService.delete(sellers.get(numBeforeDelete-1).getId());
// 記錄數應該應該等於刪除前的數量減一
Assertions.assertEquals(numBeforeDelete-1, sellerService.get().size());
List<Buyer> buyers = buyerService.get();
// 先記刪除前的總數
numBeforeDelete = buyers.size();
// 刪除最後一條記錄
buyerService.delete(buyers.get(numBeforeDelete-1).getId());
// 記錄數應該應該等於刪除前的數量減一
Assertions.assertEquals(numBeforeDelete-1, buyerService.get().size());
}
}
- 代碼中已經有詳細的註釋,就不多贅述了
驗證
- 請再次確認資料庫、表、記錄都已經準備就緒
- 運行單元測試類,如下圖,一切符合預期
- 去資料庫看一下,如下圖紅框所示,那是執行testUpdate方法時更新的結果
- 至此,quarkus連接多個資料庫的實戰操作已完成,希望這個實用技能可以給您一些參考
源碼下載
- 本篇實戰的完整源碼可在GitHub下載到,地址和鏈接信息如下表所示(https://github.com/zq2599/blog_demos)
名稱 | 鏈接 | 備註 |
---|---|---|
項目主頁 | 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文件夾下,如下圖紅框
- quarkus-tutorials是個父工程,裡面有多個module,本篇實戰的module是multi-db-demo,如下圖紅框