Commit d49db8eaa8b9fdc2df4716b9a15f7a14e8526d0b
1 parent
27e2996c
feat: find_in_set函数的跨数据库实现
Showing
4 changed files
with
159 additions
and
2 deletions
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 | } | ... | ... |