1. 程式人生 > 實用技巧 >【SpringBoot DB 系列】Jooq 初體驗

【SpringBoot DB 系列】Jooq 初體驗

【SpringBoot DB 系列】Jooq 初體驗

java 環境中,說到資料庫的操作,我們通常會想到的是 mybatis 或者 hibernate,今天給大家介紹一個國內可能用得不太多的操作方式 JOOQ,一款基於 Java 訪問關係型資料庫的工具包,輕量,簡單,並且足夠靈活的 ORM 框架

本文將各位小夥伴演示一下 jooq 整合 springboot 的姿勢

I. 專案搭建

我們這裡藉助 h2dabase 來搭建演示專案,因此有興趣的小夥伴在文末可以直接獲取專案地址啟動即可體驗,不需要額外的安裝和配置 mysql 了

本文采用SpringBoot 2.2.1.RELEASE + maven 3.5.3

+ IDEA進行開發

1. pom 依賴

下面給出核心的依賴配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

2. 配置

接下來設定一下資料庫相關的配置資訊,在資源目錄resources下,新建配置檔案application.properties

#Database Configuration
spring.datasource.url=jdbc:h2:~/h2-jooq-db
spring.datasource.username=test
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver

3. 資料庫初始化

jooq 有一個特點,是需要我們自己來生成表結構物件,所以我們先初始化一下 h2dabase 的資料結構,詳情可以參考博文 【DB 系列 h2databse 整合示例 demo】

表結構定義檔案schema-h2.sql, 請注意表結構與 mysql 的表建立姿勢不太一樣哦

DROP TABLE IF EXISTS poet;

CREATE TABLE poet (
  `id` int NOT NULL,
  `name` varchar(20) NOT NULL default '',
  CONSTRAINT pk_t_poet PRIMARY KEY (ID)
);

資料初始化data-h2.sql

INSERT INTO `poet` (`id`, `name`)
VALUES
	(1, '李白'),
	(2, '艾可翁'),
	(3, '敖陶孫'),
	(4, '安稹'),
	(5, '艾性夫'),
	(6, '奧敦周卿'),
	(7, '安鏖'),
	(8, '阿魯威'),
	(9, '安鴻漸'),
	(10, '安邑坊女');

我們接下來藉助 maven 外掛來初始化資料, pom.xml檔案中,新增如下配置

<!-- The H2 test schema is loaded here -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>sql-maven-plugin</artifactId>

    <executions>
        <execution>
            <id>create-database-h2</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>execute</goal>
            </goals>
        </execution>
    </executions>

    <configuration>
        <driver>org.h2.Driver</driver>
        <url>jdbc:h2:~/h2-jooq-db</url>
        <username>test</username>
        <password></password>
        <autocommit>true</autocommit>
        <srcFiles>
            <srcFile>src/main/resources/schema-h2.sql</srcFile>
            <srcFile>src/main/resources/data-h2.sql</srcFile>
        </srcFiles>
    </configuration>

    <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
        </dependency>
    </dependencies>
</plugin>

如下圖的 case,完成資料的初始化

II. 體驗 case

在實際開始 jooq 的 curd 之前,需要先生成對應的表結構物件,這裡也是藉助 maven 外掛來完成

1. 程式碼自動生成

同樣在pom.xml中新增如下配置

<plugin>
      <groupId>org.jooq</groupId>
      <artifactId>jooq-codegen-maven</artifactId>

      <executions>
          <execution>
              <id>generate-h2</id>
              <phase>generate-sources</phase>
              <goals>
                  <goal>generate</goal>
              </goals>
          </execution>
      </executions>
      <configuration>
          <jdbc>
              <!-- 資料庫相關配置 -->
              <driver>org.h2.Driver</driver>
              <url>jdbc:h2:~/h2-jooq-db</url>
              <username>test</username>
              <password></password>
          </jdbc>
          <generator>
              <database>
                  <!-- 資料庫的基本資訊 -->
                  <name>org.jooq.meta.h2.H2Database</name>
                  <includes>.*</includes>
                  <excludes></excludes>
                  <inputSchema>PUBLIC</inputSchema>
              </database>
              <generate>
                  <deprecated>false</deprecated>
                  <instanceFields>true</instanceFields>
                  <pojos>true</pojos>
              </generate>
              <target>
                  <!-- 自動生成的類的包名,以及路徑 -->
                  <packageName>com.git.hui.boot.jooq.h2</packageName>
                  <directory>src/main/java</directory>
              </target>
          </generator>
      </configuration>
  </plugin>

如上圖的方式執行完畢之後,會得到生成的程式碼

2. CURD

接下來我們給出 CURD 的基本使用姿勢

import static com.git.hui.boot.jooq.h2.tables.Poet.POET;

@Service
public class PoetService {

    @Autowired
    DSLContext dsl;

    public int create(int id, String author) {
        return dsl.insertInto(POET).set(POET.ID, id).set(POET.NAME, author).execute();
    }

    public PoetRecord get(int id) {
        return dsl.selectFrom(POET).where(POET.ID.eq(id)).fetchOne();
    }

    public int update(int id, String author) {
        return dsl.update(POET).set(POET.NAME, author).where(POET.ID.eq(id)).execute();
    }

    public int delete(int id) {
        return dsl.delete(POET).where(POET.ID.eq(id)).execute();
    }

    public List<PoetRecord> getAll() {
        return dsl.selectFrom(POET).fetch();
    }
}

注意上面的使用,很好理解了,基本上能愉快的寫 sql,就可以愉快的使用 jooq,上面的這種鏈式寫法,對於 sql 的閱讀是非常友好的;這裡的重點是DSLContext,它是JooqAutoConfiguration自動載入的,這裡直接拿來使用了(關於更多的配置與多資料來源的問題,後面介紹)

3. 測試 case

在 pom 中引入web依賴,設計一些基本的測試 case

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

增刪改查 case

@RestController
public class PoetRest {
    @Autowired
    private PoetService poetService;

    @RequestMapping(path = "add")
    public int add(Integer id, String name) {
        return poetService.create(id, name);
    }

    @GetMapping(path = "get")
    public String get(Integer id) {
        PoetRecord record = poetService.get(id);
        return r2str(record);
    }

    @GetMapping(path = "list")
    public List<String> list() {
        List<PoetRecord> list = poetService.getAll();
        return list.stream().map(this::r2str).collect(Collectors.toList());
    }


    @GetMapping(path = "update")
    public int update(int id, String author) {
        return poetService.update(id, author);
    }

    @GetMapping(path = "del")
    public int delete(int id) {
        return poetService.delete(id);
    }


    private String r2str(PoetRecord record) {
        return record.getId() + " # " + record.getName();
    }
}

實測結果如下

4. 小結

到此,SpringBoot 整合 jooq 的 demo 已經完成,並提供了基礎的 CURD,整體來看,整合比較簡單,需要注意的是程式碼自動生成,我們這裡是藉助 maven 外掛來實現程式碼自動生成的, 此外也可以通過官方提供的jooq-xx.jar + xml配置檔案來自動生成;後面單獨撈一篇博文給與介紹

從 jooq 的使用姿勢來看,最大的感官就是類 sql 的鏈式寫法,比較的直觀,閱讀友好;此外需要注意的是自動生成的實體PoetRecord,不要暴露出去哦,一般推薦使用 jooq 包下面的Poet來代替PoetRecord來作為 BO 物件使用,可以通過RecordMapper來實現轉換,如下

public Poet getById(int id) {
    PoetRecord record = dsl.selectFrom(POET).where(POET.ID.eq(id)).fetchOne();
    RecordMapper<PoetRecord, Poet> mapper =
            dsl.configuration().recordMapperProvider().provide(POET.recordType(), POET.getClass());
    return mapper.map(record);
}

II. 其他

0. 專案

1. 一灰灰 Blog

盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激

下面一灰灰的個人部落格,記錄所有學習和工作中的博文,歡迎大家前去逛逛