在一次學(xué)習(xí)分布式跟蹤系統(tǒng)zipkin中,發(fā)現(xiàn)了jooq這個(gè)組件,當(dāng)時(shí)不知這個(gè)組件是干嘛的,后來抽空學(xué)習(xí)了一下,感覺這個(gè)組件還挺用的。它主要有以下作用:
- 通過DSL(Domain Specific Language )風(fēng)格,利用Java代碼寫sql。
- 支持主流的RDMS和更多的特性,如self-joins,union,存儲(chǔ)過程,復(fù)雜的子查詢等。
- 提供GenerationTool,能夠通過表結(jié)構(gòu)自動(dòng)生成代碼。
Flyway是一款開源的數(shù)據(jù)庫(kù)版本管理工具,它更傾向于規(guī)約優(yōu)于配置的方式。Flyway可以獨(dú)立于應(yīng)用實(shí)現(xiàn)管理并跟蹤數(shù)據(jù)庫(kù)變更,支持?jǐn)?shù)據(jù)庫(kù)版本自動(dòng)升級(jí)。說直白一點(diǎn),F(xiàn)lyway就是做數(shù)據(jù)庫(kù)版本控制的,在數(shù)據(jù)庫(kù)版本升級(jí)中很有作用。
本文通過一個(gè)整合實(shí)例,來簡(jiǎn)單說明Jooq的用法,該例子我也提交到GitHub上,鏈接為:https://github.com/lzj09/sw-jooq
下面開始講解整合的過程。
1、pom.xml文件
其實(shí)整合的過程,大部分的工作都是在pom文件里面完成,只要看懂了pom文件,整合過程基本上就明白了。pom文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.swnote.jooq</groupId>
<artifactId>sw-jooq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>sw-jooq</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jooq相關(guān)包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta</artifactId>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen</artifactId>
</dependency>
<!-- flyway相關(guān)包 -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<!-- mysql驅(qū)動(dòng) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 用于加載application.yml信息,在pom文件可讀取到application.yml中信息 -->
<plugin>
<groupId>it.ozimov</groupId>
<artifactId>yaml-properties-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>src/main/resources/application.yml</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
<!-- flyway的插件配置 -->
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>migrate</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 此處的信息是讀取的application.yml中的信息 -->
<url>${spring.datasource.url}</url>
<user>${spring.datasource.username}</user>
<password>${spring.datasource.password}</password>
<locations>
<location>filesystem:src/main/resources/db/migration</location>
</locations>
</configuration>
</plugin>
<!-- jooq插件配置 -->
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
<execution>
<id>jooq</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<jdbc>
<driver>${spring.datasource.driverClassName}</driver>
<url>${spring.datasource.url}</url>
<user>${spring.datasource.username}</user>
<password>${spring.datasource.password}</password>
</jdbc>
<!-- 自動(dòng)生成代碼的配置 -->
<generator>
<database>
<name>org.jooq.util.mysql.MySQLDatabase</name>
<includes>.*</includes>
<excludes></excludes>
<dateAsTimestamp>true</dateAsTimestamp>
<!-- 連接的是數(shù)據(jù)庫(kù)中jooq模式 -->
<inputSchema>jooq</inputSchema>
</database>
<generate>
<deprecated>false</deprecated>
<instanceFields>true</instanceFields>
<pojos>true</pojos>
</generate>
<target>
<!-- 指定自動(dòng)生成代碼的位置 -->
<packageName>com.swnote.jooq.generator</packageName>
<directory>src/main/java</directory>
</target>
</generator>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
其中需要說明的幾個(gè)關(guān)鍵點(diǎn):
- yaml-properties-maven-plugin,該插件可以使在pom文件中讀取到application.yml文件中的配置,這樣可以避免同樣的配置有多次配置的問題。
- flyway-maven-plugin,該插件用于配置flyway,指定了創(chuàng)表的sql的位置為src/main/resources/db/migration
- jooq-codegen-maven,配置了所連接的數(shù)據(jù)庫(kù)信息,模式名,以及自動(dòng)生成的代碼的配置,比如要生成哪些代碼、將生成的代碼放在哪個(gè)目錄中等。
2、基于Jooq的CURD
由于Jooq支持通過Java代碼來寫sql的邏輯,為此例子工程中沒有Dao層,sql的邏輯全部在Service層,Service層的代碼如下:
用戶信息服務(wù)接口:IUserService
package com.swnote.jooq.service;
import java.util.List;
import java.util.Map;
import com.swnote.jooq.generator.tables.pojos.User;
/**
* 用戶信息服務(wù)接口
*
* @author lzj
* @date [2019-03-10]
*/
public interface IUserService {
/**
* 創(chuàng)建用戶
*
* @param user
*/
void create(User user);
/**
* 根據(jù)id刪除用戶
*
* @param user_id
*/
void delete(String user_id);
/**
* 更新用戶
*
* @param user
*/
void update(User user);
/**
* 根據(jù)id獲取用戶
*
* @param user_id
* @return
*/
User retrieve(String user_id);
/**
* 根據(jù)條件獲取用戶列表
*
* @param params
* @return
*/
List<User> queryForList(Map<String, Object> params);
}
用戶信息服務(wù)類:UserService
package com.swnote.jooq.service.impl;
import static com.swnote.jooq.generator.tables.User.USER;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jooq.DSLContext;
import org.jooq.UpdateQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.swnote.jooq.generator.tables.pojos.User;
import com.swnote.jooq.generator.tables.records.UserRecord;
import com.swnote.jooq.service.IUserService;
/**
* 用戶信息服務(wù)類
*
* @author lzj
* @date [2019-03-10]
*/
@Transactional
@Service
public class UserService implements IUserService {
@Autowired
private DSLContext dsl;
@Override
public void create(User user) {
// 構(gòu)建insert語(yǔ)句
dsl.insertInto(USER, USER.USER_ID, USER.NAME, USER.INTRO)
.values(user.getUserId(), user.getName(), user.getIntro()).execute();
}
@Override
public void delete(String user_id) {
// 構(gòu)建delete語(yǔ)句
dsl.delete(USER).where(USER.USER_ID.eq(user_id)).execute();
}
@Override
public void update(User user) {
// 構(gòu)建update語(yǔ)句
UpdateQuery<UserRecord> update = dsl.updateQuery(USER);
update.addValue(USER.NAME, user.getName());
update.addValue(USER.INTRO, user.getIntro());
update.addConditions(USER.USER_ID.eq(user.getUserId()));
update.execute();
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public User retrieve(String user_id) {
// 構(gòu)建select語(yǔ)句
List<User> users = dsl.select(USER.USER_ID, USER.NAME, USER.INTRO).from(USER).where(USER.USER_ID.eq(user_id))
.fetch().into(User.class);
if (users != null && !users.isEmpty()) {
return users.get(0);
}
return null;
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public List<User> queryForList(Map<String, Object> params) {
// 構(gòu)建select語(yǔ)句
StringBuilder builder = new StringBuilder();
if (params != null) {
for (Entry<String, Object> entry : params.entrySet()) {
if (builder.length() == 0) {
builder.append(entry.getKey()).append(" = ").append(entry.getValue());
} else {
builder.append(" and ").append(entry.getKey()).append(" = ").append(entry.getValue());
}
}
}
List<User> users = dsl.select(USER.USER_ID, USER.NAME, USER.INTRO).from(USER).where(builder.toString()).fetch().into(User.class);
return users;
}
}
從上面的代碼可以看到利用Jooq來寫sql的邏輯,也很簡(jiǎn)單。
3、測(cè)試
Controller層代碼在此就不寫,感興趣的可以我的GitHub中去看。在此通過PostMan測(cè)試Controller中暴露的REST接口。例如新增接口:

執(zhí)行后,數(shù)據(jù)庫(kù)也就有了記錄,即:

關(guān)注我
以你最方便的方式關(guān)注我:
微信公眾號(hào):
