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

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

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

jOOQ 是一個(gè)輕量級(jí)的 Java ORM(對(duì)象關(guān)系映射)框架,可用來構(gòu)建復(fù)雜的 SQL 查詢。jOOQ 可以根據(jù)數(shù)據(jù)庫表自動(dòng)生成對(duì)應(yīng)的 Java 類,且字段類型與數(shù)據(jù)庫一一對(duì)應(yīng),減少了 SQL 注入的風(fēng)險(xiǎn)。

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

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

Java:20(BellSoft LibericaJDK)

Maven:3.9.2

MySQL:8.1.0

jOOQ:3.18.6

Spring Boot:3.1.3

1 準(zhǔn)備數(shù)據(jù)庫、表和測(cè)試數(shù)據(jù)

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

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

如下為完整的建庫、建表和數(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)建學(xué)生表
DROP TABLE IF EXISTS student;
CREATE TABLE student (
  no INT NOT NULL,                   -- 編號(hào)
  name VARCHAR(20) NOT NULL,         -- 姓名
  gender ENUM('男', '女') NOT NULL,  -- 性別
  birthday DATETIME,                 -- 出生日期
  CONSTRAINT PRIMARY KEY (no)        -- 編號(hào)為主鍵
);

-- 為學(xué)生表插入數(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,             -- 編號(hào)
  name VARCHAR(20) NOT NULL,   -- 名稱
  CONSTRAINT PRIMARY KEY (no)  -- 編號(hào)為主鍵
);

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

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

-- 為成績(jī)表插入數(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 代碼了(主要是表相關(guān)的 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 的一個(gè)主要目的可能是想借力其豐富的 SQL 構(gòu)造能力。

下面即會(huì)使用 jOOQ 以及在第二部分生成的 Java 代碼(主要是表相關(guān)的類和 POJO 類)來實(shí)現(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)建了一個(gè)數(shù)據(jù)庫連接;然后使用DSL.using(conn, SQLDialect.MYSQL);來創(chuàng)建了DSLContext對(duì)象;然后即可以用DSLContext來像寫 SQL 語句一樣(context.selectFrom(STUDENT).fetchInto(Student.class);)來拼裝查詢語句了,查詢結(jié)果會(huì)自動(dòng)轉(zhuǎn)換為 POJO 類的類型,非常方便快捷。

程序運(yùn)行結(jié)果如下:

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

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

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);
});

上面的查詢涉及三個(gè)表的連接,依然可以像寫 SQL 一樣來進(jìn)行構(gòu)造。

程序運(yùn)行結(jié)果如下:

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

其對(duì)應(yīng)的 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 的使用非常的簡(jiǎn)單。針對(duì)單表的查詢,可以直接將結(jié)果映射到 POJO 類;對(duì)于多表連接等復(fù)雜查詢,拼裝起來也并不復(fù)雜,且結(jié)果可以轉(zhuǎn)換為一個(gè)多值的類RecordN<?, ?, ?, ...>。

4 jOOQ 與 Spring Boot 的集成

第三部分的示例僅適用于本地測(cè)試的情形,對(duì)于實(shí)際的項(xiàng)目,還需要考慮其如何與框架進(jìn)行集成。

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

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

在 Spring Boot 中使用 jOOQ 時(shí),DSLContext如何進(jìn)行創(chuàng)建,這些交給spring-boot-starter-jooq就可以了,我們依然在application.xml采用通用的數(shù)據(jù)庫配置即可,DSLContext會(huì)由 Spring 容器自動(dòng)創(chuàng)建,我們只需在需要的地方進(jìn)行自動(dò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 也支持自動(dòng)生成 DAO 層,但其生成的 DAO 層代碼比較泛化,有很多方法可能根本就用不著。所以,經(jīng)過調(diào)研后,本人決定僅使用其構(gòu)建 SQL 的能力(以及自動(dòng)生成的表相關(guān)的類和 POJO 類),DAO 層還是根據(jù)業(yè)務(wù)情形自己來實(shí)現(xiàn)比較好一些。

如下即是為 Student 查詢?cè)O(shè)計(jì)的 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();
    }

}

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

    if-else語句是控制流程的基本工具,但過度使用會(huì)使代碼變得復(fù)雜且難以維護(hù),在SpringBoot , SpringCloud項(xiàng)目中,優(yōu)化if-else結(jié)構(gòu)變得尤為重要,本文將深入探討七種策略,旨在減少SpringBoot , SpringCloud項(xiàng)目中 if-else的使用,需要的朋友可以參考下
    2024-07-07
  • Java面向?qū)ο笾畠?nèi)部類詳解

    Java面向?qū)ο笾畠?nèi)部類詳解

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

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

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

    Java多線程Thread基礎(chǔ)學(xué)習(xí)

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

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

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

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

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

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

    Java的泛型是偽泛型,那是因?yàn)榉盒托畔⒅淮嬖谟诖a編譯階段,在生成的字節(jié)碼中是不包含泛型中的類型信息的,使用泛型的時(shí)候加上類型參數(shù),在編譯器編譯的時(shí)候會(huì)去掉,這個(gè)過程為類型擦除,這篇文章主要介紹了Java?泛型中的通配符,需要的朋友可以參考下
    2022-06-06

最新評(píng)論