Commit 5f9d4b36a77e7ec06028c49765346012dc5a9432
Committed by
Gitee
!994 feat: find_in_set函数的跨数据库实现
Merge pull request !994 from dhb52/feature/db
Showing
6 changed files
with
164 additions
and
8 deletions
sql/tools/README.md
| ... | ... | @@ -55,7 +55,7 @@ docker load -i dm8_20230808_rev197096_x86_rh6_64_single.tar |
| 55 | 55 | ```Bash |
| 56 | 56 | docker compose up -d dm8 |
| 57 | 57 | # 注意:启动完 dm 后,需要手动再执行如下命令,因为 dm 不支持初始化脚本 |
| 58 | -docker compose exec dm8 bash -c "exec /opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql" | |
| 58 | +docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql' | |
| 59 | 59 | exit |
| 60 | 60 | ``` |
| 61 | 61 | |
| ... | ... | @@ -67,7 +67,8 @@ exit |
| 67 | 67 | |
| 68 | 68 | ① 下载人大金仓 Docker 镜像: |
| 69 | 69 | |
| 70 | -> x86_64 版本: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar | |
| 70 | +> x86_64 版本: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar | |
| 71 | + | |
| 71 | 72 | > aarch64 版本:https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar |
| 72 | 73 | |
| 73 | 74 | ② 加载镜像文件,在镜像 tar 文件所在目录运行: |
| ... | ... | @@ -80,12 +81,10 @@ docker load -i x86_64/kdb_x86_64_V009R001C001B0025.tar |
| 80 | 81 | |
| 81 | 82 | ```Bash |
| 82 | 83 | docker compose up -d kingbase |
| 83 | -# 注意:启动完 kingbase 后,需要手动再执行如下命令,因为 kingbase 不支持初始化脚本 | |
| 84 | +# 注意:启动完 kingbase 后,需要手动再执行如下命令 | |
| 84 | 85 | docker compose exec kingbase bash -c 'ksql -U $DB_USER -d test -f /tmp/schema.sql' |
| 85 | 86 | ``` |
| 86 | 87 | |
| 87 | -**注意**: MyBatis、MyBatis Plus 目前不兼容人大金仓,推荐直接使用 PostgreSQL JDBC 驱动,已经 url 配置方式连接数据库。 | |
| 88 | - | |
| 89 | 88 | ### 1.7 华为 OpenGauss |
| 90 | 89 | |
| 91 | 90 | ```Bash | ... | ... |
sql/tools/docker-compose.yaml
| ... | ... | @@ -93,7 +93,7 @@ services: |
| 93 | 93 | volumes: |
| 94 | 94 | - dm8:/opt/dmdbms/data |
| 95 | 95 | - ../dm/ruoyi-vue-pro-dm8.sql:/tmp/schema.sql:ro |
| 96 | - # docker compose exec dm8 bash -c "exec /opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql" | |
| 96 | + # docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql' | |
| 97 | 97 | |
| 98 | 98 | kingbase: |
| 99 | 99 | # x86_64: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/FindInSetEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.enums; | |
| 2 | + | |
| 3 | + | |
| 4 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 5 | +import lombok.AllArgsConstructor; | |
| 6 | +import lombok.Getter; | |
| 7 | + | |
| 8 | +import java.util.Arrays; | |
| 9 | +import java.util.Map; | |
| 10 | +import java.util.Optional; | |
| 11 | +import java.util.stream.Collectors; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * find_in_set函数的跨数据库实现 | |
| 15 | + * | |
| 16 | + * @author dhb52 | |
| 17 | + */ | |
| 18 | +@Getter | |
| 19 | +@AllArgsConstructor | |
| 20 | +public enum FindInSetEnum { | |
| 21 | + | |
| 22 | + // FIND_IN_SET: MySQL 类型 | |
| 23 | + MYSQL("FIND_IN_SET('#{value}', #{column}) <> 0", DbType.MYSQL), | |
| 24 | + DM("FIND_IN_SET('#{value}', #{column}) <> 0", DbType.DM), | |
| 25 | + | |
| 26 | + // INSTR: Oracle 类型 | |
| 27 | + ORACLE("INSTR(','||#{column}||',' , ',#{value},') <> 0", DbType.ORACLE), | |
| 28 | + | |
| 29 | + // CHARINDEX: SQLServer | |
| 30 | + SQLSERVER("CHARINDEX(',' + #{value} + ',', ',' + #{column} + ',')", DbType.SQL_SERVER), | |
| 31 | + | |
| 32 | + // POSITION: PostgreSQL 类型 | |
| 33 | + POSTGRE_SQL("POSITION('#{value}' IN #{column})", DbType.POSTGRE_SQL), | |
| 34 | + KINGBASE_ES("POSITION('#{value}' IN #{column})", DbType.KINGBASE_ES), | |
| 35 | + | |
| 36 | + // LOCATE: 其他 | |
| 37 | + H2("LOCATE('#{value}' IN #{column})", DbType.H2), | |
| 38 | + ; | |
| 39 | + | |
| 40 | + public static final Map<DbType, String> MAPS = Arrays.stream(values()) | |
| 41 | + .collect(Collectors.toMap(FindInSetEnum::getDbType, FindInSetEnum::getSqlTemplate)); | |
| 42 | + | |
| 43 | + private String sqlTemplate; | |
| 44 | + private DbType dbType; | |
| 45 | + | |
| 46 | + public static String getTemplate(DbType dbType) { | |
| 47 | + return Optional.of(MAPS.get(dbType)) | |
| 48 | + .orElseThrow(() -> new IllegalArgumentException("FIND_IN_SET not supported")); | |
| 49 | + } | |
| 50 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/NameToTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.enums; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 4 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 5 | +import lombok.AllArgsConstructor; | |
| 6 | +import lombok.Getter; | |
| 7 | + | |
| 8 | +import java.util.Arrays; | |
| 9 | +import java.util.Map; | |
| 10 | +import java.util.stream.Collectors; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 数据库产品名 => mp DbType 的映射关系 | |
| 14 | + * | |
| 15 | + * @author dhb52 | |
| 16 | + */ | |
| 17 | +@Getter | |
| 18 | +@AllArgsConstructor | |
| 19 | +public enum NameToTypeEnum { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * MySQL | |
| 23 | + */ | |
| 24 | + MY_SQL("MySQL", DbType.MYSQL), | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * Oracle | |
| 28 | + */ | |
| 29 | + ORACLE("Oracle", DbType.ORACLE), | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * PostgreSQL | |
| 33 | + */ | |
| 34 | + POSTGRE_SQL("PostgreSQL", DbType.POSTGRE_SQL), | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * SQL Server | |
| 38 | + */ | |
| 39 | + SQL_SERVER("Microsoft SQL Server", DbType.SQL_SERVER), | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 达梦 | |
| 43 | + */ | |
| 44 | + DM("DM DBMS", DbType.DM), | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * 人大金仓 | |
| 48 | + */ | |
| 49 | + KINGBASE_ES("KingbaseES", DbType.KINGBASE_ES), | |
| 50 | + | |
| 51 | + // 华为openGauss ProductName 与 PostgreSQL相同 | |
| 52 | + ; | |
| 53 | + | |
| 54 | + private final String name; | |
| 55 | + private final DbType type; | |
| 56 | + | |
| 57 | + public static final Map<String, DbType> MAPS = Arrays.stream(values()) | |
| 58 | + .collect(Collectors.toMap(NameToTypeEnum::getName, NameToTypeEnum::getType)); | |
| 59 | + | |
| 60 | + public static DbType find(String databaseProductName) { | |
| 61 | + if (StrUtil.isBlank(databaseProductName)) { | |
| 62 | + return null; | |
| 63 | + } | |
| 64 | + return MAPS.get(databaseProductName); | |
| 65 | + } | |
| 66 | +} | |
| 0 | 67 | \ No newline at end of file | ... | ... |
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 cn.iocoder.yudao.framework.common.util.spring.SpringUtils; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.enums.NameToTypeEnum; | |
| 5 | +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; | |
| 3 | 6 | import com.baomidou.mybatisplus.annotation.DbType; |
| 4 | 7 | |
| 8 | +import javax.sql.DataSource; | |
| 5 | 9 | import java.sql.Connection; |
| 10 | +import java.sql.DatabaseMetaData; | |
| 6 | 11 | import java.sql.DriverManager; |
| 12 | +import java.sql.SQLException; | |
| 7 | 13 | |
| 8 | 14 | /** |
| 9 | 15 | * JDBC 工具类 |
| ... | ... | @@ -38,4 +44,22 @@ public class JdbcUtils { |
| 38 | 44 | return com.baomidou.mybatisplus.extension.toolkit.JdbcUtils.getDbType(url); |
| 39 | 45 | } |
| 40 | 46 | |
| 47 | + /** | |
| 48 | + * 通过当前数据库连接获得对应的 DB 类型 | |
| 49 | + * | |
| 50 | + * @return DB 类型 | |
| 51 | + */ | |
| 52 | + public static DbType getDbType() { | |
| 53 | + DynamicRoutingDataSource dynamicRoutingDataSource = SpringUtils.getBean(DynamicRoutingDataSource.class); | |
| 54 | + DataSource dataSource = dynamicRoutingDataSource.determineDataSource(); | |
| 55 | + try (Connection conn = dataSource.getConnection()) { | |
| 56 | + DatabaseMetaData metaData = conn.getMetaData(); | |
| 57 | + String databaseProductName = metaData.getDatabaseProductName(); | |
| 58 | + DbType dbType = NameToTypeEnum.find(databaseProductName); | |
| 59 | + return dbType; | |
| 60 | + } catch (SQLException e) { | |
| 61 | + throw new IllegalArgumentException(e.getMessage()); | |
| 62 | + } | |
| 63 | + } | |
| 64 | + | |
| 41 | 65 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
| 1 | 1 | package cn.iocoder.yudao.framework.mybatis.core.util; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollectionUtil; |
| 4 | +import cn.hutool.core.util.StrUtil; | |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.pojo.SortingField; |
| 7 | +import cn.iocoder.yudao.framework.mybatis.core.enums.FindInSetEnum; | |
| 8 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 6 | 9 | import com.baomidou.mybatisplus.core.metadata.OrderItem; |
| 7 | 10 | import com.baomidou.mybatisplus.core.toolkit.StringPool; |
| 8 | 11 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| ... | ... | @@ -34,7 +37,7 @@ public class MyBatisUtils { |
| 34 | 37 | // 排序字段 |
| 35 | 38 | if (!CollectionUtil.isEmpty(sortingFields)) { |
| 36 | 39 | page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? |
| 37 | - OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField())) | |
| 40 | + OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField())) | |
| 38 | 41 | .collect(Collectors.toList())); |
| 39 | 42 | } |
| 40 | 43 | return page; |
| ... | ... | @@ -56,7 +59,7 @@ public class MyBatisUtils { |
| 56 | 59 | |
| 57 | 60 | /** |
| 58 | 61 | * 获得 Table 对应的表名 |
| 59 | - * | |
| 62 | + * <p> | |
| 60 | 63 | * 兼容 MySQL 转义表名 `t_xxx` |
| 61 | 64 | * |
| 62 | 65 | * @param table 表 |
| ... | ... | @@ -85,4 +88,18 @@ public class MyBatisUtils { |
| 85 | 88 | return new Column(tableName + StringPool.DOT + column); |
| 86 | 89 | } |
| 87 | 90 | |
| 91 | + /** | |
| 92 | + * 跨数据库的 find_in_set 实现 | |
| 93 | + * | |
| 94 | + * @param column 字段名称 | |
| 95 | + * @param value 查询值(不带单引号) | |
| 96 | + * @return sql | |
| 97 | + */ | |
| 98 | + public static String findInSet(String column, Object value) { | |
| 99 | + // 这里不用SqlConstants.DB_TYPE,因为它是使用 primary 数据源的 url 推断出来的类型 | |
| 100 | + DbType dbType = JdbcUtils.getDbType(); | |
| 101 | + return FindInSetEnum.getTemplate(dbType) | |
| 102 | + .replace("#{column}", column) | |
| 103 | + .replace("#{value}", StrUtil.toString(value)); | |
| 104 | + } | |
| 88 | 105 | } | ... | ... |