前言:
公司的BI项目采取的是SpringBoot + Jooq + postgresql 组织形势,现在将这个配置过程,详细记录下来。
Jooq和MyBatis和spring data jpa作用是一样的,都是用来链接操作数据库的。
Jooq的优点:
(1)、DSL(Domain Specific Language )风格,代码够简单和清晰。遇到不会写的sql可以充分利用IDEA代码提示功能轻松完成。
(2)、保留了传统ORM 的优点,简单操作性,安全性,类型安全等。不需要复杂的配置,并且可以利用Java 8 Stream API 做更加复杂的数据转换。
(3)、支持主流的RDMS和更多的特性,如self-joins,union,存储过程,复杂的子查询等等。
(4)、丰富的Fluent API和完善文档。
(5)、runtime schema mapping 可以支持多个数据库schema访问。简单来说使用一个连接池可以访问N个DB schema,使用比较多的就是SaaS应用的多租户场景。
好了,不多啰嗦了,Jooq的详细文档还是请大家,看官方文档:https://www.jooq.org/
公司的项目是采用gradle 组织的,gradle和maven是一样的,但是gradle的配置文件更清晰,maven的xml组织形式,啰嗦长,看着就晕,不简洁。有关gradle和maven的相关详细使用方法的请参考gradle和maven的官网。
闲话少劳聊,直接上build.gradle代码,在代码注释中详细说明每个配置的详细的作用:
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE' #springboot版本
id 'java' #标识是java项目
id 'nu.studer.jooq' version '3.0.3' #jooq的版本号
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'jacoco' #引入生成文档的jar包
group = 'com.jingdata.asset.manage.bi' #略
version = '0.0.1-SNAPSHOT' #略
sourceCompatibility = '1.8' #java版本
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-jooq' #springboot对jooq直接支持,jooq的springboot的starter
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.aspectj:aspectjrt:1.6.11'
implementation 'org.aspectj:aspectjweaver:1.6.11'
implementation 'cglib:cglib:2.1'
implementation 'org.springframework:spring-aop:4.3.9.RELEASE'
implementation 'io.springfox:springfox-swagger2:2.8.0'
implementation 'io.springfox:springfox-swagger-ui:2.8.0'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1'
compile("org.togglz:togglz-spring-boot-starter:2.6.1.Final")
runtimeOnly 'org.postgresql:postgresql' #postgresql的链接支持
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok:1.18.2'
jooqRuntime 'postgresql:postgresql:9.1-901-1.jdbc4' #postgresql的链接支持
}
test {
include '**/*Test.class' #单元测试命令,执行gradle test命令只会执行测试文件中以Test结尾的文件中的所有的测试方法。
}
task testInteg(type: Test) {
include '**/*Integ.class' #单元测试命令,执行gradle testInteg命令只会执行测试文件中以Integ结尾的文件中的所有的测试方法。
#之所以需要gradle test , gradle testInteg两个命令,是因为有些我们这里需要区分涉及外部依赖(redis,mongodb,pg数据库,elasticsearch等)的单元测试,和不涉及外部依赖的单元测试(内存中执行就行),几十个组件的集成测试时,组件之间彼此需要依赖彼此产生的数据时,h2之类的内存数据库,就不能满足测试需要了,跑一次gradle testInteg 命令,把需要的数据保存在redis,mongodb,pg数据库,elasticsearch 等中。
#公司的项目要求,每次git push提交代码和jenkins部署项目的时候需要执行一下gradle test 命令,确认修改的代码没有破坏以前的功能。
#测试同事在整个系统集成的时候,需要执行gradle test , gradle testInteg两个命令,其中gradle test经常执行,gradle testInteg 在系统几十个模块集成的时候,会执行。
}
#jooq配置,自动生成数据库表和字段的对应关系的一系列的java class文件
jooq {
version = '3.11.9'
edition = 'OSS'
sample(sourceSets.main) {
jdbc {
driver = 'org.postgresql.Driver' #jooq链接数据库的驱动
url = 'jdbc:postgresql://127.0.0.1:5432/invest111' #数据库链接地址
user = 'inves111' #连接数据库的用户名
password = 'invest111' #连接数据库的密码
}
generator {
name = 'org.jooq.codegen.DefaultGenerator'
strategy {
name = 'org.jooq.codegen.DefaultGeneratorStrategy'
// ...
}
database() {
name = 'org.jooq.meta.postgres.PostgresDatabase'
inputSchema = 'public' #只生成public schema中的表
includes='paas_bi_.*|paas_datarights_.*|paas_mt_.*|paas_auth_.*|paas_org_.*' #只需要paas_bi 、 paas_datarights、paas_mt、paas_auth、paas_org 开头的一系列的表。
}
generate() {}
target {
packageName = 'com.jingdata.asset.manage.bi.assetmanagesystem.bidb' #生成文件夹的名字
directory = 'src/main/java' #生成文件所在的目录
}
}
}
}
settings.gradle文件的内容:
pluginManagement {
repositories {
gradlePluginPortal()
}
}
rootProject.name = 'asset-manage-system'
所有这些配置完成后,就会如图所示,执行这个命令,就会把数据库中的表自动生成出来:
![1564371259390](https://yqfile.alicdn.com/23bcb12200ad1136ea627ee340584ecdcae8e30d.jpeg)
我们执行gradle test命令结果如下:
![2222](https://yqfile.alicdn.com/0457c862e6b19e4203ba81d8e772391c194d0730.jpeg)
会在项目的目录下生成一个build文件夹,这个目录下会有本次执行单元测试生成的单元测试报告,单元测试报告打开后是这样一个效果:
![4444](https://yqfile.alicdn.com/4d75c24182206129c9e068eaf038c909b314981b.jpeg)
gradle testInteg命令生成的单元测试也在这里,我这里就不赘述了。
这一部分是jooq自动生成的对应的数据库的表的java文件:
![6666](https://yqfile.alicdn.com/c209be982f43530097f82b35871a919929a8ea30.jpeg)
项目的src/main/resources下的application.properties文件中的配置内容:
server.port=8006
spring.datasource.url = jdbc:postgresql://127.0.0.1:5432/invest111
spring.datasource.driver-class-nam = org.postgresql.Driver
spring.datasource.username = invest111
spring.datasource.password = invest111
spring.datasource.minIdle = 5
spring.datasource.maxActive = 50
spring.datasource.maxWait = 60000
spring.datasource.timeBetweenEvictionRunsMillis = 60000
spring.datasource.minEvictableIdleTimeMillis = 300000
spring.datasource.validationQuery = SELECT 1 FROM DUAL
spring.datasource.testWhileIdle = true
spring.datasource.testOnBorrow = false
spring.datasource.testOnReturn = false
spring.datasource.poolPreparedStatements = true
spring.datasource.maxPoolPreparedStatementPerConnectionSize = 20
spring.datasource.connectionProperties = druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.jooq.sql-dialect = postgres
bi.http.port = 8006
bi.client.host = clientbi.2222.com
#日志相关配置
logging.file= ./logs/jingdata-bi-pg
logging.level.root= ERROR
logging.level.com.jingdata= DEBUG
logging.level.org.springframework.web= DEBUG
logging.level.com.netflix.discovery.DiscoveryClien= OFF
logging.level.com.netflix.discovery.InstanceInfoReplicator= OFF
基本是一看就行,也就不啰嗦了。
下面再给出,一些使用jooq在postgresql 数据中的表中做CURD操作的代码,不啰嗦,直接上,几乎是一看就懂:
package com.jingdata.asset.manage.bi.assetmanagesystem.system.impl;
import com.jingdata.asset.manage.bi.assetmanagesystem.system.function.IAnnouncementReferencesService;
import com.jingdata.asset.manage.bi.assetmanagesystem.system.impl.base.BaseImpl;
import com.jingdata.asset.manage.bi.assetmanagesystem.transform.ReferenceInfoVo;
import com.jingdata.asset.manage.bi.assetmanagesystem.transform.ReferenceTransform;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.impl.DSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.List;
import static com.jingdata.asset.manage.bi.assetmanagesystem.bidb.Tables.PAAS_BI_ANNOUNCEMENT_REFERENCES;
/**
* @date 2019-02-28
*
*/
@Service
public class AnnouncementReferencesImpl extends BaseImpl implements IAnnouncementReferencesService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private ReferenceTransform referenceTransform = new ReferenceTransform();
@Override
public List<ReferenceInfoVo> getOneAnnouncementReferences(Integer announcementId) {
Result<Record> records = getDSLContext().select().from(PAAS_BI_ANNOUNCEMENT_REFERENCES)
.where(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.USER_ID).eq("5bcfd9f06faa7b79fd28c304"))
.and(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.IS_DELETED).eq(0))
.and(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.REFERENCE_ID).eq(announcementId))
.orderBy(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.ID).desc())
.fetch();
return referenceTransform.transformReferenceRecord(records);
}
@Override
public Integer addOneAnnouncementReferences(Integer announcementId, String reportList, String chartList) {
return getDSLContext().insertInto(PAAS_BI_ANNOUNCEMENT_REFERENCES)
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.APP_ID), "1111122222")
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.USER_ID), "1111122222")
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.TENANT_ID), "1111122222")
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.CREATED_BY), "1111122222")
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.UPDATED_BY), "1111122222")
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.IS_DELETED), 0)
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.UPDATED_AT), new Timestamp(System.currentTimeMillis()))
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.CREATED_AT), new Timestamp(System.currentTimeMillis()))
//1表示报表,2表示图表
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.REFERENCE_TYPE), 1)
//1表示报表,2表示图表
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.REFERENCE_ID), Integer.parseInt("111"))
//1表示报表,2表示图表
.set(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.SOURCE_ID), announcementId)
.execute();
}
@Override
public Integer deleteOneAnnouncementReferences(String referenceIds) {
return getDSLContext().delete(PAAS_BI_ANNOUNCEMENT_REFERENCES)
.where(DSL.field(PAAS_BI_ANNOUNCEMENT_REFERENCES.ID).eq(Integer.parseInt(referenceIds))).execute();
}
@Override
public void deleteByMasterChartId(Long masterId, Context context) {
dslContext.update(PAAS_BI_DASHBOARD_LINKAGE)
.set(PAAS_BI_DASHBOARD_LINKAGE.IS_DELETED, 1)
.set(PAAS_BI_DASHBOARD_LINKAGE.UPDATE_BY, context.getUserId())
.set(PAAS_BI_DASHBOARD_LINKAGE.UPDATE_TIME, System.currentTimeMillis())
.where(PAAS_BI_DASHBOARD_LINKAGE.MASTER_CHART_ID.eq(masterId))
.and(PAAS_BI_DASHBOARD_LINKAGE.TENANT_ID.eq(context.getTenantId()))
.and(PAAS_BI_DASHBOARD_LINKAGE.APP_ID.eq(context.getAppId()))
.and(PAAS_BI_DASHBOARD_LINKAGE.IS_DELETED.eq(0))
.execute();
}
}
基本上增、删、改、查都有了。
更高级的用法,jion 、union等相关写法,请参考jooq的官方文档。
本周会给出在码云上的git 源码的链接地址,如果有疑问的,请参考源码,代码胜千言!!!!!