diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/FindInSetEnum.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/FindInSetEnum.java new file mode 100644 index 000000000..298d0dd9d --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/FindInSetEnum.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.framework.mybatis.core.enums; + + +import com.baomidou.mybatisplus.annotation.DbType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * find_in_set函数的跨数据库实现 + * + * @author dhb52 + */ +@Getter +@AllArgsConstructor +public enum FindInSetEnum { + + // FIND_IN_SET: MySQL 类型 + MYSQL("FIND_IN_SET('#{value}', #{column}) <> 0", DbType.MYSQL), + DM("FIND_IN_SET('#{value}', #{column}) <> 0", DbType.DM), + + // INSTR: Oracle 类型 + ORACLE("INSTR(','||#{column}||',' , ',#{value},') <> 0", DbType.ORACLE), + + // CHARINDEX: SQLServer + SQLSERVER("CHARINDEX(',' + #{value} + ',', ',' + #{column} + ',')", DbType.SQL_SERVER), + + // POSITION: PostgreSQL 类型 + POSTGRE_SQL("POSITION('#{value}' IN #{column})", DbType.POSTGRE_SQL), + KINGBASE_ES("POSITION('#{value}' IN #{column})", DbType.KINGBASE_ES), + + // LOCATE: 其他 + H2("LOCATE('#{value}' IN #{column})", DbType.H2), + ; + + public static final Map MAPS = Arrays.stream(values()) + .collect(Collectors.toMap(FindInSetEnum::getDbType, FindInSetEnum::getSqlTemplate)); + + private String sqlTemplate; + private DbType dbType; + + public static String getTemplate(DbType dbType) { + return Optional.of(MAPS.get(dbType)) + .orElseThrow(() -> new IllegalArgumentException("FIND_IN_SET not supported")); + } +} diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/NameToTypeEnum.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/NameToTypeEnum.java new file mode 100644 index 000000000..065f702e4 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/NameToTypeEnum.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.framework.mybatis.core.enums; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.DbType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 数据库产品名 => mp DbType 的映射关系 + * + * @author dhb52 + */ +@Getter +@AllArgsConstructor +public enum NameToTypeEnum { + + /** + * MySQL + */ + MY_SQL("MySQL", DbType.MYSQL), + + /** + * Oracle + */ + ORACLE("Oracle", DbType.ORACLE), + + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL", DbType.POSTGRE_SQL), + + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server", DbType.SQL_SERVER), + + /** + * 达梦 + */ + DM("DM DBMS", DbType.DM), + + /** + * 人大金仓 + */ + KINGBASE_ES("KingbaseES", DbType.KINGBASE_ES), + + // 华为openGauss ProductName 与 PostgreSQL相同 + ; + + private final String name; + private final DbType type; + + public static final Map MAPS = Arrays.stream(values()) + .collect(Collectors.toMap(NameToTypeEnum::getName, NameToTypeEnum::getType)); + + public static DbType find(String databaseProductName) { + if (StrUtil.isBlank(databaseProductName)) { + return null; + } + return MAPS.get(databaseProductName); + } +} \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java index b98a907c1..532162c2a 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.framework.mybatis.core.util; +import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; +import cn.iocoder.yudao.framework.mybatis.core.enums.NameToTypeEnum; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.mybatisplus.annotation.DbType; +import javax.sql.DataSource; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.DriverManager; +import java.sql.SQLException; /** * JDBC 工具类 @@ -38,4 +44,22 @@ public class JdbcUtils { return com.baomidou.mybatisplus.extension.toolkit.JdbcUtils.getDbType(url); } + /** + * 通过当前数据库连接获得对应的 DB 类型 + * + * @return DB 类型 + */ + public static DbType getDbType() { + DynamicRoutingDataSource dynamicRoutingDataSource = SpringUtils.getBean(DynamicRoutingDataSource.class); + DataSource dataSource = dynamicRoutingDataSource.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + DbType dbType = NameToTypeEnum.find(databaseProductName); + return dbType; + } catch (SQLException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java index 3da059a6c..789bf75c9 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.framework.mybatis.core.util; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.SortingField; +import cn.iocoder.yudao.framework.mybatis.core.enums.FindInSetEnum; +import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; @@ -34,7 +37,7 @@ public class MyBatisUtils { // 排序字段 if (!CollectionUtil.isEmpty(sortingFields)) { page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? - OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField())) + OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField())) .collect(Collectors.toList())); } return page; @@ -56,7 +59,7 @@ public class MyBatisUtils { /** * 获得 Table 对应的表名 - * + *

* 兼容 MySQL 转义表名 `t_xxx` * * @param table 表 @@ -85,4 +88,18 @@ public class MyBatisUtils { return new Column(tableName + StringPool.DOT + column); } + /** + * 跨数据库的 find_in_set 实现 + * + * @param column 字段名称 + * @param value 查询值(不带单引号) + * @return sql + */ + public static String findInSet(String column, Object value) { + // 这里不用SqlConstants.DB_TYPE,因为它是使用 primary 数据源的 url 推断出来的类型 + DbType dbType = JdbcUtils.getDbType(); + return FindInSetEnum.getTemplate(dbType) + .replace("#{column}", column) + .replace("#{value}", StrUtil.toString(value)); + } }