Commit 98c317f0e0775b6bc95d7fdcc6936ef9513a98b3
1 parent
2367280d
封装 IdTypeEnvironmentPostProcessor 组件,自动适配 id-type 策略,用于 Oracle、PostgreSQL 的自动适配
Showing
10 changed files
with
148 additions
and
17 deletions
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
| ... | ... | @@ -42,6 +42,10 @@ |
| 42 | 42 | <groupId>com.oracle.database.jdbc</groupId> |
| 43 | 43 | <artifactId>ojdbc8</artifactId> |
| 44 | 44 | </dependency> |
| 45 | + <dependency> | |
| 46 | + <groupId>org.postgresql</groupId> | |
| 47 | + <artifactId>postgresql</artifactId> | |
| 48 | + </dependency> | |
| 45 | 49 | |
| 46 | 50 | <dependency> |
| 47 | 51 | <groupId>com.alibaba</groupId> | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.config; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; | |
| 6 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 7 | +import com.baomidou.mybatisplus.annotation.IdType; | |
| 8 | +import lombok.extern.slf4j.Slf4j; | |
| 9 | +import org.springframework.boot.SpringApplication; | |
| 10 | +import org.springframework.boot.env.EnvironmentPostProcessor; | |
| 11 | +import org.springframework.core.env.ConfigurableEnvironment; | |
| 12 | + | |
| 13 | +import java.util.Set; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 当 IdType 为 {@link IdType#NONE} 时,根据 PRIMARY 数据源所使用的数据库,自动设置 | |
| 17 | + * | |
| 18 | + * @author 芋道源码 | |
| 19 | + */ | |
| 20 | +@Slf4j | |
| 21 | +public class IdTypeEnvironmentPostProcessor implements EnvironmentPostProcessor { | |
| 22 | + | |
| 23 | + private static final String ID_TYPE_KEY = "mybatis-plus.global-config.db-config.id-type"; | |
| 24 | + | |
| 25 | + private static final String DATASOURCE_DYNAMIC_KEY = "spring.datasource.dynamic"; | |
| 26 | + | |
| 27 | + private static final Set<DbType> INPUT_ID_TYPES = SetUtils.asSet(DbType.ORACLE, DbType.ORACLE_12C, | |
| 28 | + DbType.POSTGRE_SQL, DbType.KINGBASE_ES, DbType.DB2, DbType.H2); | |
| 29 | + | |
| 30 | + @Override | |
| 31 | + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { | |
| 32 | + // 如果非 NONE,则不进行处理 | |
| 33 | + IdType idType = getIdType(environment); | |
| 34 | + if (idType != IdType.NONE) { | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + // 如果获取不到 DbType,则不进行处理 | |
| 38 | + DbType dbType = getDbType(environment); | |
| 39 | + if (dbType == null) { | |
| 40 | + return; | |
| 41 | + } | |
| 42 | + | |
| 43 | + // 情况一,用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 | |
| 44 | + if (INPUT_ID_TYPES.contains(dbType)) { | |
| 45 | + setIdType(environment, IdType.INPUT); | |
| 46 | + return; | |
| 47 | + } | |
| 48 | + // 情况二,自增 ID,适合 MySQL 等直接自增的数据库 | |
| 49 | + setIdType(environment, IdType.AUTO); | |
| 50 | + } | |
| 51 | + | |
| 52 | + public IdType getIdType(ConfigurableEnvironment environment) { | |
| 53 | + return environment.getProperty(ID_TYPE_KEY, IdType.class); | |
| 54 | + } | |
| 55 | + | |
| 56 | + public void setIdType(ConfigurableEnvironment environment, IdType idType) { | |
| 57 | + environment.getSystemProperties().put(ID_TYPE_KEY, idType); | |
| 58 | + log.info("[setIdType][修改 MyBatis Plus 的 idType 为({})]", idType); | |
| 59 | + } | |
| 60 | + | |
| 61 | + public static DbType getDbType(ConfigurableEnvironment environment) { | |
| 62 | + String primary = environment.getProperty(DATASOURCE_DYNAMIC_KEY + "." + "primary"); | |
| 63 | + if (StrUtil.isEmpty(primary)) { | |
| 64 | + return null; | |
| 65 | + } | |
| 66 | + String url = environment.getProperty(DATASOURCE_DYNAMIC_KEY + ".datasource." + primary + ".url"); | |
| 67 | + if (StrUtil.isEmpty(url)) { | |
| 68 | + return null; | |
| 69 | + } | |
| 70 | + return JdbcUtils.getDbType(url); | |
| 71 | + } | |
| 72 | + | |
| 73 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
| 1 | 1 | package cn.iocoder.yudao.framework.mybatis.config; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler; |
| 5 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 4 | 6 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
| 7 | +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; | |
| 8 | +import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator; | |
| 9 | +import com.baomidou.mybatisplus.extension.incrementer.KingbaseKeyGenerator; | |
| 10 | +import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator; | |
| 11 | +import com.baomidou.mybatisplus.extension.incrementer.PostgreKeyGenerator; | |
| 5 | 12 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 6 | 13 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
| 7 | 14 | import org.apache.ibatis.annotations.Mapper; |
| 8 | 15 | import org.mybatis.spring.annotation.MapperScan; |
| 16 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
| 9 | 17 | import org.springframework.context.annotation.Bean; |
| 10 | 18 | import org.springframework.context.annotation.Configuration; |
| 19 | +import org.springframework.core.env.ConfigurableEnvironment; | |
| 11 | 20 | |
| 12 | 21 | /** |
| 13 | 22 | * MyBaits 配置类 |
| ... | ... | @@ -31,4 +40,25 @@ public class YudaoMybatisAutoConfiguration { |
| 31 | 40 | return new DefaultDBFieldHandler(); // 自动填充参数类 |
| 32 | 41 | } |
| 33 | 42 | |
| 43 | + @Bean | |
| 44 | + @ConditionalOnProperty(prefix = "mybatis-plus.global-config.db-config", name = "id-type", havingValue = "INPUT") | |
| 45 | + public IKeyGenerator keyGenerator(ConfigurableEnvironment environment) { | |
| 46 | + DbType dbType = IdTypeEnvironmentPostProcessor.getDbType(environment); | |
| 47 | + if (dbType != null) { | |
| 48 | + switch (dbType) { | |
| 49 | + case POSTGRE_SQL: | |
| 50 | + return new PostgreKeyGenerator(); | |
| 51 | + case ORACLE: | |
| 52 | + case ORACLE_12C: | |
| 53 | + return new OracleKeyGenerator(); | |
| 54 | + case H2: | |
| 55 | + return new H2KeyGenerator(); | |
| 56 | + case KINGBASE_ES: | |
| 57 | + return new KingbaseKeyGenerator(); | |
| 58 | + } | |
| 59 | + } | |
| 60 | + // 找不到合适的 IKeyGenerator 实现类 | |
| 61 | + throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType)); | |
| 62 | + } | |
| 63 | + | |
| 34 | 64 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java
| 1 | 1 | package cn.iocoder.yudao.framework.mybatis.core.util; |
| 2 | 2 | |
| 3 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 4 | + | |
| 3 | 5 | import java.sql.Connection; |
| 4 | 6 | import java.sql.DriverManager; |
| 5 | 7 | |
| ... | ... | @@ -26,4 +28,15 @@ public class JdbcUtils { |
| 26 | 28 | } |
| 27 | 29 | } |
| 28 | 30 | |
| 31 | + /** | |
| 32 | + * 获得 URL 对应的 DB 类型 | |
| 33 | + * | |
| 34 | + * @param url URL | |
| 35 | + * @return DB 类型 | |
| 36 | + */ | |
| 37 | + public static DbType getDbType(String url) { | |
| 38 | + String name = com.alibaba.druid.util.JdbcUtils.getDbType(url, null); | |
| 39 | + return DbType.getDbType(name); | |
| 40 | + } | |
| 41 | + | |
| 29 | 42 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories
| 1 | 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
| 2 | 2 | cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration,\ |
| 3 | 3 | cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration |
| 4 | +org.springframework.boot.env.EnvironmentPostProcessor=\ | |
| 5 | + cn.iocoder.yudao.framework.mybatis.config.IdTypeEnvironmentPostProcessor | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/errorcode/core/generator/ErrorCodeAutoGeneratorImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.system.framework.errorcode.core.generator; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.exceptions.ExceptionUtil; | |
| 4 | 5 | import cn.hutool.core.util.ClassUtil; |
| 5 | 6 | import cn.hutool.core.util.ReflectUtil; |
| 6 | 7 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| ... | ... | @@ -57,7 +58,7 @@ public class ErrorCodeAutoGeneratorImpl implements ErrorCodeAutoGenerator { |
| 57 | 58 | * |
| 58 | 59 | * @return 错误码数组 |
| 59 | 60 | */ |
| 60 | - private List<ErrorCodeAutoGenerateReqDTO> parseErrorCode() { | |
| 61 | + private List<ErrorCodeAutoGenerateReqDTO> parseErrorCode() { | |
| 61 | 62 | // 校验 errorCodeConstantsClass 参数 |
| 62 | 63 | if (CollUtil.isEmpty(constantsClassList)) { |
| 63 | 64 | log.info("[execute][未配置 yudao.error-code.constants-class-list 配置项,不进行自动写入到 system 服务中]"); |
| ... | ... | @@ -67,10 +68,15 @@ public class ErrorCodeAutoGeneratorImpl implements ErrorCodeAutoGenerator { |
| 67 | 68 | // 解析错误码 |
| 68 | 69 | List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs = new ArrayList<>(); |
| 69 | 70 | constantsClassList.forEach(constantsClass -> { |
| 70 | - // 解析错误码枚举类 | |
| 71 | - Class<?> errorCodeConstantsClazz = ClassUtil.loadClass(constantsClass); | |
| 72 | - // 解析错误码 | |
| 73 | - autoGenerateDTOs.addAll(parseErrorCode(errorCodeConstantsClazz)); | |
| 71 | + try { | |
| 72 | + // 解析错误码枚举类 | |
| 73 | + Class<?> errorCodeConstantsClazz = ClassUtil.loadClass(constantsClass); | |
| 74 | + // 解析错误码 | |
| 75 | + autoGenerateDTOs.addAll(parseErrorCode(errorCodeConstantsClazz)); | |
| 76 | + } catch (Exception ex) { | |
| 77 | + log.warn("[parseErrorCode][constantsClass({}) 加载失败({})]", constantsClass, | |
| 78 | + ExceptionUtil.getRootCauseMessage(ex)); | |
| 79 | + } | |
| 74 | 80 | }); |
| 75 | 81 | return autoGenerateDTOs; |
| 76 | 82 | } | ... | ... |
yudao-server/pom.xml
| ... | ... | @@ -43,11 +43,11 @@ |
| 43 | 43 | <version>${revision}</version> |
| 44 | 44 | </dependency> |
| 45 | 45 | <!-- 默认引入 yudao-module-bpm-biz-flowable 实现,可以替换为 yudao-module-bpm-biz-activiti 实现--> |
| 46 | - <dependency> | |
| 47 | - <groupId>cn.iocoder.boot</groupId> | |
| 48 | - <artifactId>yudao-module-bpm-biz-flowable</artifactId> | |
| 49 | - <version>${revision}</version> | |
| 50 | - </dependency> | |
| 46 | +<!-- <dependency>--> | |
| 47 | +<!-- <groupId>cn.iocoder.boot</groupId>--> | |
| 48 | +<!-- <artifactId>yudao-module-bpm-biz-flowable</artifactId>--> | |
| 49 | +<!-- <version>${revision}</version>--> | |
| 50 | +<!-- </dependency>--> | |
| 51 | 51 | <!-- <dependency>--> |
| 52 | 52 | <!-- <groupId>cn.iocoder.boot</groupId>--> |
| 53 | 53 | <!-- <artifactId>yudao-module-bpm-biz-activiti</artifactId>--> | ... | ... |
yudao-server/src/main/resources/application-dev.yaml
| ... | ... | @@ -36,7 +36,7 @@ spring: |
| 36 | 36 | time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 |
| 37 | 37 | min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 |
| 38 | 38 | max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 |
| 39 | - validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 | |
| 39 | + validation-query: SELECT 1 # 配置检测连接是否有效 | |
| 40 | 40 | test-while-idle: true |
| 41 | 41 | test-on-borrow: false |
| 42 | 42 | test-on-return: false | ... | ... |
yudao-server/src/main/resources/application-local.yaml
| ... | ... | @@ -36,7 +36,7 @@ spring: |
| 36 | 36 | time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 |
| 37 | 37 | min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 |
| 38 | 38 | max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 |
| 39 | - validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 | |
| 39 | + validation-query: SELECT 1 # 配置检测连接是否有效 | |
| 40 | 40 | test-while-idle: true |
| 41 | 41 | test-on-borrow: false |
| 42 | 42 | test-on-return: false |
| ... | ... | @@ -44,14 +44,14 @@ spring: |
| 44 | 44 | datasource: |
| 45 | 45 | master: |
| 46 | 46 | name: ruoyi-vue-pro |
| 47 | - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT | |
| 48 | - driver-class-name: com.mysql.jdbc.Driver | |
| 47 | +# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL 连接的示例 | |
| 48 | + url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 | |
| 49 | 49 | username: root |
| 50 | 50 | password: 123456 |
| 51 | 51 | slave: # 模拟从库,可根据自己需要修改 |
| 52 | 52 | name: ruoyi-vue-pro |
| 53 | - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT | |
| 54 | - driver-class-name: com.mysql.jdbc.Driver | |
| 53 | +# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL 连接的示例 | |
| 54 | + url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 | |
| 55 | 55 | username: root |
| 56 | 56 | password: 123456 |
| 57 | 57 | ... | ... |
yudao-server/src/main/resources/application.yaml
| ... | ... | @@ -54,7 +54,10 @@ mybatis-plus: |
| 54 | 54 | map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 |
| 55 | 55 | global-config: |
| 56 | 56 | db-config: |
| 57 | - id-type: AUTO # 自增 ID | |
| 57 | + id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 | |
| 58 | +# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 | |
| 59 | +# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 | |
| 60 | +# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 | |
| 58 | 61 | logic-delete-value: 1 # 逻辑已删除值(默认为 1) |
| 59 | 62 | logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) |
| 60 | 63 | type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject | ... | ... |