SpringCloud系列----->SpringBoot项目中整合jooq和postgresql数据库

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: 前言: 公司的BI项目采取的是SpringBoot + Jooq + postgresql 组织形势,现在将这个配置过程,详细记录下来。 Jooq和MyBatis和spring data jpa作用是一样的,都是用来链接操作数据库的。
前言:
    公司的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 源码的链接地址,如果有疑问的,请参考源码,代码胜千言!!!!!
  
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
1月前
|
NoSQL Java 数据库
【问题篇】springboot项目通过数据库限制实例端口号
【问题篇】springboot项目通过数据库限制实例端口号
19 0
|
1月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
1月前
|
SpringCloudAlibaba Java 持续交付
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
155 0
|
1月前
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
588 0
|
2天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
8天前
|
SQL 监控 druid
Druid数据库连接池简介及应用推广(老项目翻出来做下记录)
Druid数据库连接池简介及应用推广(老项目翻出来做下记录)
|
24天前
|
开发框架 负载均衡 Java
Spring boot与Spring cloud之间的关系
总之,Spring Boot和Spring Cloud之间的关系是一种构建和扩展的关系,Spring Boot提供了基础,而Spring Cloud在此基础上提供了分布式系统和微服务架构所需的扩展和工具。
18 4
Spring boot与Spring cloud之间的关系
|
1月前
|
存储 关系型数据库 MySQL
TiDB与MySQL、PostgreSQL等数据库的比较分析
【2月更文挑战第25天】本文将对TiDB、MySQL和PostgreSQL等数据库进行详细的比较分析,探讨它们各自的优势和劣势。TiDB作为一款分布式关系型数据库,在扩展性、并发性能等方面表现突出;MySQL以其易用性和成熟性受到广泛应用;PostgreSQL则在数据完整性、扩展性等方面具有优势。通过对比这些数据库的特点和适用场景,帮助企业更好地选择适合自己业务需求的数据库系统。
|
1月前
|
开发工具 git 微服务
【二十三】搭建SpringCloud项目六(Config)配置中心动态刷新
【二十三】搭建SpringCloud项目六(Config)配置中心动态刷新
19 0
|
1月前
|
Java 开发工具 git
【二十二】搭建SpringCloud项目六(Config)配置中心
【二十二】搭建SpringCloud项目六(Config)配置中心
32 0