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

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: 前言: 公司的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数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
28天前
|
Java 数据库连接 测试技术
SpringBoot入门 - 添加内存数据库H2
SpringBoot入门 - 添加内存数据库H2
39 3
SpringBoot入门 - 添加内存数据库H2
|
1月前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
52 4
SpringBoot入门(4) - 添加内存数据库H2
|
22天前
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
70 5
|
24天前
|
Java 关系型数据库 数据库连接
使用 Spring Boot 执行数据库操作:全面指南
使用 Spring Boot 执行数据库操作:全面指南
84 1
|
2月前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
36 2
SpringBoot入门(4) - 添加内存数据库H2
|
1月前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
68 13
|
1月前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
47 4
|
2月前
|
SQL JavaScript 关系型数据库
node博客小项目:接口开发、连接mysql数据库
【10月更文挑战第14天】node博客小项目:接口开发、连接mysql数据库
|
2月前
|
SQL 关系型数据库 MySQL
Go语言项目高效对接SQL数据库:实践技巧与方法
在Go语言项目中,与SQL数据库进行对接是一项基础且重要的任务
90 11
|
1月前
|
存储 安全 Java
springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
`@ConfigurationProperties`注解和数据库存储配置信息各有优劣,适用于不同的应用场景。`@ConfigurationProperties`提供了类型安全和模块化的配置管理方式,适合静态和简单配置。而数据库存储配置信息提供了动态更新和集中管理的能力,适合需要频繁变化和集中管理的配置需求。在实际项目中,可以根据具体需求选择合适的配置管理方式,或者结合使用这两种方式,实现灵活高效的配置管理。
24 0