Commit d49db8eaa8b9fdc2df4716b9a15f7a14e8526d0b

Authored by dhb52
1 parent 27e2996c

feat: find_in_set函数的跨数据库实现

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 }
... ...