quarkus数据库篇之三:单应用同时操作多个数据库

这篇具有很好参考价值的文章主要介绍了quarkus数据库篇之三:单应用同时操作多个数据库。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 一个应用同时连接多个数据库进行操作,这是常见的场景,quarkus也不例外,今天就随本文一起来实战多数据源操作
  • 如下图,今天要创建名为multi-db-demo的应用,此应用同时连接两个数据库,名为fist-db的库中是卖家表,名为second-db的库中是买家表
quarkus数据库篇之三:单应用同时操作多个数据库
  • 为了简化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);
  • 再整理一下两个数据库的地址,稍后用到
  1. MySQL:jdbc:mysql://192.168.50.43:3306/first_db
  2. 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地址、账号密码等,如下图
quarkus数据库篇之三:单应用同时操作多个数据库
  • 这里再强调一下配置的内容:配置的是数据源(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中都要有数据源名称,下图是默认数据源和非默认数据源配置项的对比,红色内容是数据源名称,放在第二个点号后面
quarkus数据库篇之三:单应用同时操作多个数据库
  • 按照上述规则,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());
    }
}
  • 代码中已经有详细的注释,就不多赘述了

验证

  • 请再次确认数据库、表、记录都已经准备就绪
  • 运行单元测试类,如下图,一切符合预期
quarkus数据库篇之三:单应用同时操作多个数据库
  • 去数据库看一下,如下图红框所示,那是执行testUpdate方法时更新的结果
quarkus数据库篇之三:单应用同时操作多个数据库
  • 至此,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) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本次实战的源码在quarkus-tutorials文件夹下,如下图红框
    quarkus数据库篇之三:单应用同时操作多个数据库
  • quarkus-tutorials是个父工程,里面有多个module,本篇实战的module是multi-db-demo,如下图红框
    quarkus数据库篇之三:单应用同时操作多个数据库

本篇概览

  • 一个应用同时连接多个数据库进行操作,这是常见的场景,quarkus也不例外,今天就随本文一起来实战多数据源操作
  • 如下图,今天要创建名为multi-db-demo的应用,此应用同时连接两个数据库,名为fist-db的库中是卖家表,名为second-db的库中是买家表
quarkus数据库篇之三:单应用同时操作多个数据库
  • 为了简化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);
  • 再整理一下两个数据库的地址,稍后用到
  1. MySQL:jdbc:mysql://192.168.50.43:3306/first_db
  2. 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地址、账号密码等,如下图
quarkus数据库篇之三:单应用同时操作多个数据库
  • 这里再强调一下配置的内容:配置的是数据源(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中都要有数据源名称,下图是默认数据源和非默认数据源配置项的对比,红色内容是数据源名称,放在第二个点号后面
quarkus数据库篇之三:单应用同时操作多个数据库
  • 按照上述规则,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());
    }
}
  • 代码中已经有详细的注释,就不多赘述了

验证

  • 请再次确认数据库、表、记录都已经准备就绪
  • 运行单元测试类,如下图,一切符合预期
quarkus数据库篇之三:单应用同时操作多个数据库
  • 去数据库看一下,如下图红框所示,那是执行testUpdate方法时更新的结果
quarkus数据库篇之三:单应用同时操作多个数据库
  • 至此,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) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本次实战的源码在quarkus-tutorials文件夹下,如下图红框
    quarkus数据库篇之三:单应用同时操作多个数据库
  • quarkus-tutorials是个父工程,里面有多个module,本篇实战的module是multi-db-demo,如下图红框
    quarkus数据库篇之三:单应用同时操作多个数据库

本篇概览

  • 一个应用同时连接多个数据库进行操作,这是常见的场景,quarkus也不例外,今天就随本文一起来实战多数据源操作
  • 如下图,今天要创建名为multi-db-demo的应用,此应用同时连接两个数据库,名为fist-db的库中是卖家表,名为second-db的库中是买家表
quarkus数据库篇之三:单应用同时操作多个数据库
  • 为了简化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);
  • 再整理一下两个数据库的地址,稍后用到
  1. MySQL:jdbc:mysql://192.168.50.43:3306/first_db
  2. 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地址、账号密码等,如下图
quarkus数据库篇之三:单应用同时操作多个数据库
  • 这里再强调一下配置的内容:配置的是数据源(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中都要有数据源名称,下图是默认数据源和非默认数据源配置项的对比,红色内容是数据源名称,放在第二个点号后面
quarkus数据库篇之三:单应用同时操作多个数据库
  • 按照上述规则,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());
    }
}
  • 代码中已经有详细的注释,就不多赘述了

验证

  • 请再次确认数据库、表、记录都已经准备就绪
  • 运行单元测试类,如下图,一切符合预期
quarkus数据库篇之三:单应用同时操作多个数据库
  • 去数据库看一下,如下图红框所示,那是执行testUpdate方法时更新的结果
quarkus数据库篇之三:单应用同时操作多个数据库
  • 至此,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) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本次实战的源码在quarkus-tutorials文件夹下,如下图红框
    quarkus数据库篇之三:单应用同时操作多个数据库
  • quarkus-tutorials是个父工程,里面有多个module,本篇实战的module是multi-db-demo,如下图红框
    quarkus数据库篇之三:单应用同时操作多个数据库

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...文章来源地址https://www.toymoban.com/news/detail-652256.html

到了这里,关于quarkus数据库篇之三:单应用同时操作多个数据库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何在一个系统中同时访问异构的多种数据库

    如何在一个系统中同时访问异构的多种数据库 比如在一个系统中,要同时访问MySQL,H2, MsAccess, Mongodb. 要是使用Hibernate, MyBatis这些ORM,难度简直不敢想像。 要是MySQL还使用了分库分表,那更加不得了,一大堆的组件都要配合着上,一时间整个系统的难度,复杂度就上来了。 但如

    2024年01月19日
    浏览(33)
  • Springboot + Mybatis 同时支持多类数据库SQL的解决方案

    pg、Oracle、MySQL 的字符串转日志函数不同,可通过 _databaseId 来判断该执行哪段SQL 多余的代码就不写上了,直接根据下列代码就能理解。

    2024年02月09日
    浏览(43)
  • quarkus实战之三:开发模式(Development mode)

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 前文咱们曾提到过几种启动方式,有一种用maven命令启动的,可以进入开发模式,命令如下: 当时只提到此模式能看到详细系统信息,并未展开说明更多信息,实际上,此模式下还有很多实用的功能

    2024年02月16日
    浏览(23)
  • quarkus依赖注入之三:用注解选择注入bean

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第三篇,前文咱们掌握了创建bean的几种方式,本篇趁热打铁,学习一个与创建bean有关的重要知识点:一个接口如果有多个实现类时,bean实例应该如何选择其中的一个

    2024年02月14日
    浏览(34)
  • 数据库应用:数据库管理系统与安装MySQL数据库

    目录 一、理论 1.数据库管理系统 2.关系型数据库 3.数据库 4.MySQL数据库 5.MySQL部署 二、实验 1.yum安装MySQL 2.编译安装MySQL 3.配置MySQL数据库的Tab补全  三、问题 1.数据库登录报错 2.数据库密码复杂度报错 3.数据库连接报错 四、总结 (1)概念 数据库管理系统(Database Management

    2024年02月13日
    浏览(44)
  • 数据库应用:MySQL数据库SQL高级语句与操作

    目录 一、理论 1.克隆表与清空表 2.SQL高级语句 3.SQL函数 4.SQL高级操作 5.MySQL中6种常见的约束 二、实验  1.克隆表与清空表 2.SQL高级语句 3.SQL函数 4.SQL高级操作 5.主键表和外键表  三、总结 克隆表:将数据表的数据记录生成到新的表中。 (1)克隆表 ① 先创建再导入 ② 创建

    2024年02月13日
    浏览(60)
  • 数据库应用:kylin 部署 达梦数据库DM8

    目录   一、实验 1.环境 2.部署前规划 3.部署达梦数据库DM8 4.创建数据库及数据库事例管理 5.达梦数据库的基本操作 二、问题 1.xhost命令报错 2.执行安装程序DMInstall.bin 报错 3.解压安装程序报错 4.安装程序找不到文件 5.图像化界面打不开 6.安装内存太小 7.打开图形化界面报错

    2024年02月19日
    浏览(40)
  • springboot 数据库应用

    第一章 SpringBoot起步 第二章 springboot 配置文件、多环境配置、运行优先级 第三章 springboot 统一日志 第四章 SpringBoot加载静态文件资源 第五章 springboot 拦截器 第六章 实现自定义全局异常处理 第七章 springboot 数据库应用 第八章 springboot 整合Druid 第九章 springboot 整合MyBatis - xm

    2023年04月08日
    浏览(19)
  • 数据库系统原理与应用教程(014)—— 关系数据库练习题(一)

    1、试述关系模型的三要素和关系操作语言的特点。 答案: 关系模型的三要素为数据结构、关系操作和完整性约束。在关系模型中,无论是实体集还是实体集之间的联系都是由关系表示的。 关系操作语言的特点:(1)关系操作的方式是一次一集合方式。(2)关系操作语言是

    2024年02月02日
    浏览(40)
  • MongoDB:数据库初步应用

    1.MongoDBCompass连接数据库 连接路径:mongodb://用户名:密码@localhost:27017/ 2.创建数据库(集合) MongoDB中数据库被称为集合.  MongoDBCompass连接后,点击红色框加号创建集合,点击蓝色框加号创建文档(数据表) 文档中的数据结构(相当于表中的列)设计不用管,添加数据的时候,自动创建列和数

    2024年02月12日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包