微服务架构 - SpringBoot整合Jooq和Flyway

932 阅读3分钟

在一次学习分布式跟踪系统zipkin中,发现了jooq这个组件,当时不知这个组件是干嘛的,后来抽空学习了一下,感觉这个组件还挺用的。它主要有以下作用:

通过DSL(Domain Specific Language )风格,利用Java代码写sql。 支持主流的RDMS和更多的特性,如self-joins,union,存储过程,复杂的子查询等。 提供GenerationTool,能够通过表结构自动生成代码。 Flyway是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级。说直白一点,Flyway就是做数据库版本控制的,在数据库版本升级中很有作用。

下面开始讲解整合的过程。

1、pom.xml文件

其实整合的过程,大部分的工作都是在pom文件里面完成,只要看懂了pom文件,整合过程基本上就明白了。pom文件如下:

org.springframework.boot spring-boot-starter-parent 2.0.2.RELEASE 4.0.0 com.swnote.jooq sw-jooq 0.0.1-SNAPSHOT jar sw-jooq maven.apache.org <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> org.springframework.boot spring-boot-starter-web

org.springframework.boot spring-boot-starter-jooq org.jooq jooq-meta org.jooq jooq-codegen org.flywaydb flyway-core mysql mysql-connector-java org.apache.maven.plugins maven-compiler-plugin 1.8 1.8 org.springframework.boot spring-boot-maven-plugin repackage it.ozimov yaml-properties-maven-plugin 1.1.3 initialize read-project-properties src/main/resources/application.yml org.flywaydb flyway-maven-plugin generate-sources migrate ${spring.datasource.url} ${spring.datasource.username} ${spring.datasource.password} filesystem:src/main/resources/db/migration org.jooq jooq-codegen-maven jooq generate-sources generate ${spring.datasource.driverClassName} ${spring.datasource.url} ${spring.datasource.username} ${spring.datasource.password} org.jooq.util.mysql.MySQLDatabase .* true jooq false true true com.swnote.jooq.generator src/main/java mysql mysql-connector-java 5.1.46 src/main/java **/*.java src/main/resources 其中需要说明的几个关键点:

yaml-properties-maven-plugin,该插件可以使在pom文件中读取到application.yml文件中的配置,这样可以避免同样的配置有多次配置的问题。 flyway-maven-plugin,该插件用于配置flyway,指定了创表的sql的位置为src/main/resources/db/migration jooq-codegen-maven,配置了所连接的数据库信息,模式名,以及自动生成的代码的配置,比如要生成哪些代码、将生成的代码放在哪个目录中等。 2、基于Jooq的CURD

由于Jooq支持通过Java代码来写sql的逻辑,为此例子工程中没有Dao层,sql的逻辑全部在Service层,Service层的代码如下:

用户信息服务接口:IUserService

package com.swnote.jooq.service; import java.util.List; import java.util.Map; import com.swnote.jooq.generator.tables.pojos.User; /**

  • 用户信息服务接口
  • @author lzj
  • @date [2019-03-10] / public interface IUserService { /*
  • 创建用户
  • @param user / void create(User user); /*
  • 根据id删除用户
  • @param user_id / void delete(String user_id); /*
  • 更新用户
  • @param user */ void update(User user);

/**

  • 根据id获取用户
  • @param user_id
  • @return / User retrieve(String user_id); /*
  • 根据条件获取用户列表
  • @param params
  • @return */ List queryForList(Map<String, Object> params); } 用户信息服务类: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; /**

  • 用户信息服务类
  • @author lzj
  • @date [2019-03-10] */ @Transactional @Service public class UserService implements IUserService { @Autowired private DSLContext dsl; @Override public void create(User user) { // 构建insert语句 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) { // 构建delete语句 dsl.delete(USER).where(USER.USER_ID.eq(user_id)).execute(); } @Override public void update(User user) { // 构建update语句 UpdateQuery 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) { // 构建select语句 List 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 queryForList(Map<String, Object> params) { // 构建select语句 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 users = dsl.select(USER.USER_ID, USER.NAME, USER.INTRO).from(USER).where(builder.toString()).fetch().into(User.class); return users; } } 从上面的代码可以看到利用Jooq来写sql的逻辑,也很简单。

3、测试

Controller层代码在此就不写,感兴趣的可以我的GitHub中去看。在此通过PostMan测试Controller中暴露的REST接口。例如新增接口:

执行后,数据库也就有了记录,即:

微服务架构 - SpringBoot整合Jooq和Flyway