欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析Java數(shù)據(jù)庫操作工具包jOOQ的使用

 更新時間:2024年04月03日 14:44:03   作者:磊磊落落  
jOOQ?是一個輕量級的?Java?ORM(對象關系映射)框架,可用來構建復雜的?SQL?查詢,這篇文章主要來和大家介紹一下jOOQ的使用,需要的可以參考下

jOOQ 是一個輕量級的 Java ORM(對象關系映射)框架,可用來構建復雜的 SQL 查詢。jOOQ 可以根據(jù)數(shù)據(jù)庫表自動生成對應的 Java 類,且字段類型與數(shù)據(jù)庫一一對應,減少了 SQL 注入的風險。

本文即是對 jOOQ 的初探,包括四個部分:準備數(shù)據(jù)庫和測試數(shù)據(jù)、jOOQ Java 代碼生成、jOOQ 初步使用,以及 jOOQ 與 Spring Boot 的集成。

開始各個部分前,列出本文涉及的各軟件版本:

Java:20(BellSoft LibericaJDK)

Maven:3.9.2

MySQL:8.1.0

jOOQ:3.18.6

Spring Boot:3.1.3

1 準備數(shù)據(jù)庫、表和測試數(shù)據(jù)

探索 jOOQ 的使用之前,需要有一個數(shù)據(jù)庫和幾張表。學生課程系統(tǒng)就是一個不錯的業(yè)務場景,既接近實際又涉及連表等復雜查詢,很適合用來作演示學習。

本文為學生課程系統(tǒng)創(chuàng)建了一個 school 數(shù)據(jù)庫,并在其下創(chuàng)建了三張表 student(學生表)、course(課程表)和 score(成績表)。

如下為完整的建庫、建表和數(shù)據(jù)插入語句:

-- 創(chuàng)建數(shù)據(jù)庫 school
DROP DATABASE IF EXISTS school;
CREATE DATABASE school DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

-- 使用數(shù)據(jù)庫 school
USE school;

-- 創(chuàng)建學生表
DROP TABLE IF EXISTS student;
CREATE TABLE student (
  no INT NOT NULL,                   -- 編號
  name VARCHAR(20) NOT NULL,         -- 姓名
  gender ENUM('男', '女') NOT NULL,  -- 性別
  birthday DATETIME,                 -- 出生日期
  CONSTRAINT PRIMARY KEY (no)        -- 編號為主鍵
);

-- 為學生表插入數(shù)據(jù)
INSERT INTO student VALUES
  (1, '閆浩然', '男', '1999-09-01'),
  (2, '肖雪', '女', '2000-03-21'),
  (3, '張如意', '女', '2001-08-08');

-- 創(chuàng)建課程表
DROP TABLE IF EXISTS course;
CREATE TABLE course (
  no INT NOT NULL,             -- 編號
  name VARCHAR(20) NOT NULL,   -- 名稱
  CONSTRAINT PRIMARY KEY (no)  -- 編號為主鍵
);

-- 為課程表插入數(shù)據(jù)
INSERT INTO course VALUES
  (1, '語文'),
  (2, '數(shù)學'),
  (3, '英語');

-- 創(chuàng)建成績表
DROP TABLE IF EXISTS score;
CREATE TABLE score (
  student_no INT NOT NULL,                                     -- 學生編號
  course_no INT NOT NULL,                                      -- 課程編號
  degree DECIMAL(4, 1) NOT NULL,                               -- 分數(shù)
  CONSTRAINT PRIMARY KEY (student_no, course_no),              -- 學生編號與課程編號為聯(lián)合主鍵
  CONSTRAINT FOREIGN KEY (student_no) REFERENCES student(no),  -- 學生編號為外鍵
  CONSTRAINT FOREIGN KEY (course_no) REFERENCES course(no)     -- 課程編號為外鍵
);

-- 為成績表插入數(shù)據(jù)
INSERT INTO score VALUES
  (1, 1, 90.5),
  (1, 2, 88.0),
  (1, 3, 98.0),
  (2, 1, 78.5),
  (2, 2, 68.0),
  (2, 3, 93.0),
  (3, 1, 83.0),
  (3, 2, 94.5),
  (3, 3, 73.0);

2 jOOQ Java 代碼生成

該部分嘗試用 jOOQ Maven 插件(jooq-codegen-maven)的方式來生成 Java 代碼。

本文使用的是在本地搭建的 MySQL 數(shù)據(jù)庫,將第一部分的 SQL 語句在數(shù)據(jù)庫執(zhí)行后,即可以嘗試使用 jOOQ Maven 插件來生成 Java 代碼了(主要是表相關的 Java 類和 POJO 類)。

插件jooq-codegen-maven在 Maven 配置文件pom.xml中的配置信息如下:

<plugin>
    <groupId>org.jooq</groupId>
    <artifactId>jooq-codegen-maven</artifactId>
    <version>${jooq.version}</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <jdbc>
            <driver>com.mysql.cj.jdbc.Driver</driver>
            <url>jdbc:mysql://localhost:3306/school</url>
            <user>root</user>
            <password>root</password>
        </jdbc>
        <generator>
            <generate>
                <pojos>true</pojos>
            </generate>
            <database>
                <includes>.*</includes>
                <inputSchema>school</inputSchema>
            </database>
            <target>
                <packageName>com.leileiluoluo.jooq.model.generated</packageName>
                <directory>src/main/java</directory>
            </target>
        </generator>
    </configuration>
</plugin>

然后,使用如下命令生成 Java 代碼:

mvn clean generate-sources

可以看到,代碼被生成到了src/main/java文件夾下的com.leileiluoluo.jooq.model.generated包下。

3 jOOQ 初步使用

使用 jOOQ 的一個主要目的可能是想借力其豐富的 SQL 構造能力。

下面即會使用 jOOQ 以及在第二部分生成的 Java 代碼(主要是表相關的類和 POJO 類)來實現(xiàn)一些常用的查詢。

如下即是使用 jOOQ 來查詢所有 Student 的一段示例代碼:

import com.leileiluoluo.jooq.model.generated.tables.pojos.Student;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;

import static com.leileiluoluo.jooq.model.generated.Tables.STUDENT;

public class JOOQSimpleQueryTest {

    public static void main(String[] args) {
        String username = "root";
        String password = "root";
        String url = "jdbc:mysql://localhost:3306/school";

        try (Connection conn = DriverManager.getConnection(url, username, password)) {
            DSLContext context = DSL.using(conn, SQLDialect.MYSQL);

            List<Student> students = context.selectFrom(STUDENT)
                    .fetchInto(Student.class);

            students.forEach(student -> {
                System.out.printf("no: %s, name: %s, gender: %s, birthday: %s\n", student.getNo(), student.getName(), student.getGender(), student.getBirthday());
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

可以看到,上面這段代碼首先使用DriverManager.getConnection(url, username, password);來創(chuàng)建了一個數(shù)據(jù)庫連接;然后使用DSL.using(conn, SQLDialect.MYSQL);來創(chuàng)建了DSLContext對象;然后即可以用DSLContext來像寫 SQL 語句一樣(context.selectFrom(STUDENT).fetchInto(Student.class);)來拼裝查詢語句了,查詢結果會自動轉換為 POJO 類的類型,非常方便快捷。

程序運行結果如下:

no: 1, name: 閆浩然, gender: 男, birthday: 1999-09-01T00:00
no: 2, name: 肖雪, gender: 女, birthday: 2000-03-21T00:00
no: 3, name: 張如意, gender: 女, birthday: 2001-08-08T00:00

上面的示例針對的是單表查詢的情形,下面再看一下復雜查詢的拼裝:

DSLContext context = DSL.using(conn, SQLDialect.MYSQL);

List<Record3<String, String, BigDecimal>> studentCourseScores = context.select(
                STUDENT.NAME,
                COURSE.NAME,
                SCORE.DEGREE
        ).from(SCORE)
        .join(STUDENT).on(SCORE.STUDENT_NO.eq(STUDENT.NO))
        .join(COURSE).on(SCORE.COURSE_NO.eq(COURSE.NO))
        .fetch();

studentCourseScores.forEach(record -> {
    String studentName = record.getValue(STUDENT.NAME);
    String courseName = record.getValue(COURSE.NAME);
    BigDecimal degree = record.getValue(SCORE.DEGREE);
    System.out.printf("student: %s, course: %s, degree: %s\n", studentName, courseName, degree);
});

上面的查詢涉及三個表的連接,依然可以像寫 SQL 一樣來進行構造。

程序運行結果如下:

student: 張如意, course: 語文, degree: 83.0
student: 肖雪, course: 語文, degree: 78.5
student: 閆浩然, course: 語文, degree: 90.5
student: 張如意, course: 數(shù)學, degree: 94.5
student: 肖雪, course: 數(shù)學, degree: 68.0
student: 閆浩然, course: 數(shù)學, degree: 88.0
student: 張如意, course: 英語, degree: 73.0
student: 肖雪, course: 英語, degree: 93.0
student: 閆浩然, course: 英語, degree: 98.0

其對應的 SQL 語句如下:

SELECT
    s.name,
    c.name,
    sc.degree
FROM score sc
JOIN student s
    ON sc.student_no=s.no
JOIN course c
    ON sc.course_no=c.no;

通過這兩段示例程序,即可以看到 jOOQ 的使用非常的簡單。針對單表的查詢,可以直接將結果映射到 POJO 類;對于多表連接等復雜查詢,拼裝起來也并不復雜,且結果可以轉換為一個多值的類RecordN<?, ?, ?, ...>。

4 jOOQ 與 Spring Boot 的集成

第三部分的示例僅適用于本地測試的情形,對于實際的項目,還需要考慮其如何與框架進行集成。

該部分即會探索 jOOQ 與 Spring Boot 的集成,主要會探索兩個方面:DSLContext的自動創(chuàng)建、DAO 層的封裝。

4.1 DSLContext 的自動創(chuàng)建

在 Spring Boot 中使用 jOOQ 時,DSLContext如何進行創(chuàng)建,這些交給spring-boot-starter-jooq就可以了,我們依然在application.xml采用通用的數(shù)據(jù)庫配置即可,DSLContext會由 Spring 容器自動創(chuàng)建,我們只需在需要的地方進行自動注入就可以了。

# application.yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/school
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
// StudentDao.java
@Service
public class StudentDaoImpl implements StudentDao {

    @Autowired
    private DSLContext context;

}

4.2 DAO 層的封裝

雖然 jOOQ 也支持自動生成 DAO 層,但其生成的 DAO 層代碼比較泛化,有很多方法可能根本就用不著。所以,經(jīng)過調研后,本人決定僅使用其構建 SQL 的能力(以及自動生成的表相關的類和 POJO 類),DAO 層還是根據(jù)業(yè)務情形自己來實現(xiàn)比較好一些。

如下即是為 Student 查詢設計的 StudentDao 的示例代碼:

// StudentDao.java
package com.leileiluoluo.jooq.dao;

import com.leileiluoluo.jooq.model.generated.tables.pojos.Student;

import java.util.List;
import java.util.Optional;

public interface StudentDao {

    Integer countAll();

    List<Student> listAll();

    List<Student> listWithPagination(int offset, int limit);

    Optional<Student> getByNo(Integer no);

    void save(Student record);

    void update(Student record);

    void deleteByNo(Integer no);

}
// StudentDaoImpl.java
package com.leileiluoluo.jooq.dao.impl;

import com.leileiluoluo.jooq.dao.StudentDao;
import com.leileiluoluo.jooq.model.generated.tables.pojos.Student;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

import static com.leileiluoluo.jooq.model.generated.Tables.STUDENT;

@Service
public class StudentDaoImpl implements StudentDao {

    @Autowired
    private DSLContext context;

    @Override
    public Integer countAll() {
        return context.fetchCount(STUDENT);
    }

    @Override
    public List<Student> listAll() {
        return context.selectFrom(STUDENT)
                .fetchInto(Student.class);
    }

    @Override
    public List<Student> listWithPagination(int offset, int limit) {
        return context.selectFrom(STUDENT)
                .offset(offset)
                .limit(limit)
                .fetchInto(Student.class);
    }

    @Override
    public Optional<Student> getByNo(Integer no) {
        Student student = context.select()
                .from(STUDENT)
                .where(STUDENT.NO.eq(no))
                .fetchOneInto(Student.class);

        return Optional.ofNullable(student);
    }

    @Override
    public void save(Student student) {
        context.insertInto(STUDENT)
                .set(STUDENT.NO, student.getNo())
                .set(STUDENT.NAME, student.getName())
                .set(STUDENT.GENDER, student.getGender())
                .set(STUDENT.BIRTHDAY, student.getBirthday())
                .execute();
    }

    @Override
    public void update(Student student) {
        context.update(STUDENT)
                .set(STUDENT.NAME, student.getName())
                .set(STUDENT.GENDER, student.getGender())
                .set(STUDENT.BIRTHDAY, student.getBirthday())
                .where(
                        STUDENT.NO.eq(student.getNo())
                )
                .execute();
    }

    @Override
    public void deleteByNo(Integer no) {
        context.deleteFrom(STUDENT)
                .where(
                        STUDENT.NO.eq(no)
                ).execute();
    }

}

可以看到,增、刪、改、查都有了,基本滿足了實際業(yè)務中的需要;在其上設計 Service 和 Controller 即可以實現(xiàn)真實的 REST 業(yè)務需求了。

綜上,本文準備了一些測試數(shù)據(jù),探索了 jOOQ 的代碼生成和 SQL 構建能力,最后還思考了其與 Spring Boot 的集成??傮w來看,jOOQ 還是比較易用的,是一個不錯的 MyBatis 或 Hibernate 替代方案。

以上就是淺析Java數(shù)據(jù)庫操作工具包jOOQ的使用的詳細內容,更多關于Java jOOQ數(shù)據(jù)庫操作工具包的資料請關注腳本之家其它相關文章!

相關文章

  • java serialVersionUID解決序列化類版本不一致問題面試精講

    java serialVersionUID解決序列化類版本不一致問題面試精講

    這篇文章主要為大家介紹了serialVersionUID解決序列化類版本不一致問題的面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Maven項目web多圖片上傳及格式驗證的實現(xiàn)

    Maven項目web多圖片上傳及格式驗證的實現(xiàn)

    本文主要介紹了Maven項目web多圖片上傳及格式驗證的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • MyBatis 延遲加載、一級緩存、二級緩存(詳解)

    MyBatis 延遲加載、一級緩存、二級緩存(詳解)

    下面小編就為大家?guī)硪黄狹yBatis 延遲加載、一級緩存、二級緩存(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • SpringBoot中優(yōu)化if-else語句的七種方法

    SpringBoot中優(yōu)化if-else語句的七種方法

    if-else語句是控制流程的基本工具,但過度使用會使代碼變得復雜且難以維護,在SpringBoot , SpringCloud項目中,優(yōu)化if-else結構變得尤為重要,本文將深入探討七種策略,旨在減少SpringBoot , SpringCloud項目中 if-else的使用,需要的朋友可以參考下
    2024-07-07
  • Java面向對象之內部類詳解

    Java面向對象之內部類詳解

    在 Java 中,允許一個類的定義位于另一個類的內部,前者稱為內部類,后者稱為外部類。這篇文章將總結一下內部類的使用,感興趣的可以了解一下
    2022-10-10
  • Java多線程實現(xiàn)多人聊天室功能

    Java多線程實現(xiàn)多人聊天室功能

    這篇文章主要為大家詳細介紹了Java多線程實現(xiàn)多人聊天室功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Java多線程Thread基礎學習

    Java多線程Thread基礎學習

    每一個正在執(zhí)行的程序都是一個進程,資源只有一塊,所以在同一時間段會有多個程序同時執(zhí)行,但是在一個時間點上,只能由一個程序執(zhí)行,多線程是在一個進程的基礎之上的進一步劃分,需要的朋友可以參考下
    2023-04-04
  • Java找出兩個大數(shù)據(jù)量List集合中的不同元素的方法總結

    Java找出兩個大數(shù)據(jù)量List集合中的不同元素的方法總結

    本文將帶大家了解如何快速的找出兩個相似度非常高的List集合里的不同元素。主要通過Java API、List集合雙層遍歷比較不同、借助Map集合查找三種方式,需要的可以參考一下
    2022-10-10
  • 使用@ApiModel遇到的問題及解決

    使用@ApiModel遇到的問題及解決

    這篇文章主要介紹了使用@ApiModel遇到的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 最新Java?泛型中的通配符講解

    最新Java?泛型中的通配符講解

    Java的泛型是偽泛型,那是因為泛型信息只存在于代碼編譯階段,在生成的字節(jié)碼中是不包含泛型中的類型信息的,使用泛型的時候加上類型參數(shù),在編譯器編譯的時候會去掉,這個過程為類型擦除,這篇文章主要介紹了Java?泛型中的通配符,需要的朋友可以參考下
    2022-06-06

最新評論