登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
登录
注册
代码拉取完成,页面将自动刷新
开源项目
>
数据库相关
>
数据库开发包
&&
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
253
Star
3K
Fork
591
MyBatis-Flex
/
MyBatis-Flex
代码
Issues
255
Pull Requests
9
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
507
动态数据源 @UseDataSource 的value值扩展支持表达式解析处理
已合并
Alay:main
MyBatis-Flex:main
Alay
创建于 2024-12-07 16:46
克隆/下载
HTTPS
SSH
复制
下载 Email Patch
下载 Diff 文件
## 该 PR 关联的 Issue 关联 Issue 的解决说明 无 Issue 关联 关联 Issue 的解决说明 ## 修改描述 - 第一部分 如果有需要自定义扩展需求自行扩展;如下通过session 读取: ```java public class InSessionDataSourceProcessor implements DataSourceProcessor { private static final String SESSION_PREFIX = "#session"; @Override public String process(String dataSourceKey, Object mapper, Method method, Object[] arguments) { if (StrUtil.isBlank(dataSourceKey)) return null; if (!dataSourceKey.startsWith(SESSION_PREFIX)) return null; HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); return request.getSession().getAttribute(dataSourceKey.substring(9)).toString(); } } ``` - 第二部分 实例化处理器,可以单个解析处理器实例化,如果多个实例化,建议通过 DelegatingDataSourceProcessor.with(多个解析处理器实例) 方式进行实例化。 需要注意的是表达式之间有先后顺序,一旦排列前面的解析处理器正常处理后,将直接返回处理值,不再往下传递处理。 ```java // 注入顺序既为执行时的先后顺序(前面的处理器一旦正确处理,将不会再往下传递处理) DelegatingDataSourceProcessor dataSourceProcessor = DelegatingDataSourceProcessor.with( // 参数索引快速取值的 new ParamIndexDataSourceProcessor(), // Spel 表达式的 new SpelExpressionDataSourceProcessor() ); // 实例 setter 赋值 DataSourceManager.setDataSourceProcessor(dataSourceProcessor); ``` - 第三部分 ```java @Mapper public interface MyMapper extends BaseMapper<MyEntity >{ /** * 取值第一个参数的值(arg0的值) */ @UseDataSource(value = "#first") MyEntity test1(String arg0, String arg1, String arg2); /** * 取值索引1(第二个参数 arg1 )的值 */ @UseDataSource(value = "#index1") MyEntity test2(String arg0, String arg1, String arg2); /** * 取值最后一个参数的值(arg3的值) */ @UseDataSource(value = "#last") MyEntity test3(String arg0, String arg1, String arg2, String arg3); /** * Spel 表达式取值数据源 */ @UseDataSource(value = "#condition.getDsId()") MyEntity test4(String arg0, MyDsParam condition); } ``` ## 测试用例 ### 测试用例1,注解@UseDataSource 使用到Mapper 上使用 如果同一个调佣链多处使用注解 @UseDataSource 则越接近Dao层优先级越高,如 Service 和 Mapper 上同时使用了,则 Service 中解析出来后,当执行 Mapper 时再次解析,会覆盖之前的值。 以下演示为 非 Spring 情况和 Spring 情况都支持,即不区分场景,但是引入了 Spring 场景的情况 DataSourceInterceptor 优先被执行,FlexMapperProxy就不会被执行。(DataSourceInterceptor 优先级高于FlexMapperProxy) ```java public class MyServiceImpl { private final MyMapper myMapper; public void test(){ // mapper中的注解 @UseDataSource(value = "#first") myMapper.test1("my-tenant1", "arg1", "arg2"); // 取值索引1(第二个参数)的值;mapper中的注解 @UseDataSource(value = "#index1") myMapper.test2("arg0", "my-tenant2", "arg2"); // mapper中的注解 @UseDataSource(value = "#last") myMapper.test3("arg0", "arg1", "arg2","my-tenant3"); MyDsParam condition = new MyDsParam(); condition.setDsId("my-tenant4"); // mapper中的注解 @UseDataSource(value = "#condition.getDsId()") myMapper.test4("my-tenant1",condition ); } } ``` ### 测试用例2,使用Spring情况下 通过切面处理 DataSourceInterceptor 或者 FlexMapperProxy 类中调用处理 DataSourceInterceptor 优先级高于FlexMapperProxy ;FlexMapperProxy 主要针对 非Spring项目,以下场景为 Spring场景演示,Spring下,只要切面生效,不限制注解使用的位置(Controller 、Service、Mapper 都可以),但是推荐还是使用到 Mapper (Dao) 层,其更接近数据操作,更符合控制粒度,使用在 Controller 和 Service 层则其下层调用的所有操作都会受影响,控制粒度会比较粗,受影响面大。 ##### controller ```java @GetMapping("/test/first") @Operation(summary = "first测试", description = "first测试") public R firstTest(ColumnTestModel columnTestModel) { List<TableColumn> tableColumns = datasourceTestService.firstTest(columnTestModel.getTableName(), columnTestModel.getDsId()); return R.ok(tableColumns); } @GetMapping("/test/last") @Operation(summary = "last测试", description = "last测试") public R lastTest(ColumnTestModel columnTestModel) { TableSchema tableSchema = datasourceTestService.lastTest(columnTestModel.getTableName(), columnTestModel.getDsId()); return R.ok(tableSchema); } @GetMapping("/test/index") @Operation(summary = "测试Column查询", description = "测试Column查询") public R indexTest(ColumnTestModel columnTestModel) { TableSchema tableSchema = datasourceTestService.indexTest(columnTestModel.getTableName(), columnTestModel.getDsId(), null); return R.ok(tableSchema); } @GetMapping("/test/spel") @Operation(summary = "SPEL测试Column查询", description = "SPEL测试Column查询") public R spelTest(ColumnTestModel columnTestModel) { TableSchema tableSchema = datasourceTestService.spelTest(columnTestModel); return R.ok(tableSchema); } ``` 参数Model ```java public class ColumnTestModel implements Serializable { @Serial private static final long serialVersionUID = 1L; private String dsId; private String tableName; } ``` ##### Service 接口 ```java public interface DatasourceTestService { List<TableColumn> firstTest(String dsId, String tableName); TableSchema lastTest(String tableName, String dsId); TableSchema indexTest(String tableName, String dsId, String arg2); TableSchema spelTest(ColumnTestModel columnTestModel); } ``` 实现类 ```java public class DatasourceTestServiceImpl implements DatasourceTestService { private final InSQLSchemaMapper inSQLSchemaMapper; @Override @UseDataSource(value = "#first") public List<TableColumn> firstTest(String dsId, String tableName) { return inSQLSchemaMapper.selectColumn(tableName, dsId); } @Override @UseDataSource(value = "#last") public TableSchema lastTest(String tableName, String dsId) { return inSQLSchemaMapper.selectSchema(tableName, dsId); } @Override @UseDataSource(value = "#index1") public TableSchema indexTest(String tableName, String dsId, String arg2) { return inSQLSchemaMapper.selectSchema(tableName, dsId); } @Override @UseDataSource(value = "#columnTestModel.getDsId()") public TableSchema spelTest(ColumnTestModel columnTestModel) { return inSQLSchemaMapper.selectSchema(columnTestModel.getTableName(), null); } } ``` ##### Mapper ```java /** * 查询表全部列信息 * * @param dsId 数据源Id * @param tableName 表名称 * @return */ List<TableColumn> selectColumn(@Param("tableName") String tableName, String dsId); /** * 查询表信息 * * @param tableName 表名称 * @param dsId 数据源Id * @return */ TableSchema selectSchema(@Param("tableName") String tableName, String dsId); ``` XML,基于MySQL的 ```java <resultMap id="schemaMap" type="com.kwanyon.cloud.generator.entity.TableSchema"> <result property="tableSchema" column="table_schema"/> <result property="tableName" column="table_name"/> <result property="tableType" column="table_type"/> <result property="engine" column="engine"/> <result property="rowFormat" column="row_format"/> <result property="tableComment" column="table_comment"/> <result property="tableCollation" column="table_collation"/> <result property="version" column="version"/> <result property="createTime" column="create_time"/> </resultMap> <resultMap id="columnMap" type="com.kwanyon.cloud.generator.entity.TableColumn"> <result property="tableSchema" column="table_schema"/> <result property="tableName" column="table_name"/> <result property="columnName" column="column_name"/> <result property="dataType" column="data_type"/> <result property="ordinalPosition" column="ordinal_position"/> <result property="columnDefault" column="column_default"/> <result property="isNullable" column="is_nullable"/> <result property="columnComment" column="column_comment"/> <result property="columnKey" column="column_key"/> <result property="extra" column="extra"/> <result property="columnType" column="column_type"/> </resultMap> <!-- mysql 表字段查询语句 --> <sql id="columnSql"> SELECT `table_schema`, `table_name`, `column_name`, `data_type`, `ordinal_position`, `column_default`, IF(`is_nullable` = 'YES', 1, 0) AS `is_nullable`, `column_comment`, `column_key`, `extra`, `column_type` FROM `information_schema`.`columns` </sql> <select id="selectSchema" resultMap="schemaMap"> <include refid="schemaSql"/> WHERE `table_schema` = (SELECT database() AS `db`) AND `table_name` = #{tableName} ORDER BY `create_time` DESC </select> <select id="selectColumn" resultMap="columnMap"> <include refid="columnSql"/> WHERE `table_schema` = (SELECT DATABASE() AS `db` ) <if test="tableName !=null and tableName != ''"> AND `table_name` = #{tableName} </if> ORDER BY `ordinal_position` </select> ``` ##### 实体 ```java public class TableSchema implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 数据库库名 */ private String tableSchema; /** * 表名 */ private String tableName; /** * 表类型(BASE TABLE / SYSTEM VIEW) */ private String tableType; /** * 引擎(InnoDB) */ private String engine; /** * 行格式 */ private String rowFormat; /** * 表注释 */ private String tableComment; /** * 排序规则 */ private String tableCollation; /** * 版本 */ private Integer version; /** * 创建时间 */ private LocalDateTime createTime; } ``` ```java public class TableColumn implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 库名 */ private String tableSchema; /** * 表名 */ private String tableName; /** * 字段名称(下划线格式名称) */ private String columnName; /** * 字段数据类型(VARCHAR,INT 等等) */ private String dataType; /** * 排序位置(从 1 开始) */ private Integer ordinalPosition; /** * 默认值(CURRENT_TIMESTAMP,0,b'0') */ private String columnDefault; /** * 是否允许为 null */ private Boolean isNullable; /** * 字段注释 */ private String columnComment; /** * 字段索引类型(PRI,MUL,UNI等) */ private String columnKey; /** * 其他信息(DEFAULT_GENERATED on update CURRENT_TIMESTAMP,AUTO_INCREMENT) */ private String extra; /** * 字段定义数据类型 (varchar(31)) */ private String columnType; } ```
此 Pull Request 需要通过一些审核项
类型
指派人员
状态
审查
Michael Yang
已审查通过
已完成
(1/1人)
测试
Michael Yang
已测试通过
已完成
(1/1人)
怎样手动合并此 Pull Request
git checkout main
git pull https://gitee.com/chxlay/mybatis-flex.git main
git push origin main
评论
2
提交
9
文件
11
检查
代码问题
0
批量操作
展开设置
折叠设置
审查
Code Owner
审查人员
Michael Yang
fuhai
王帅
Suomm
未设置
最少人数
1
测试
Michael Yang
fuhai
王帅
Suomm
未设置
最少人数
1
优先级
不指定
严重
主要
次要
不重要
标签
标签管理
未设置
关联 Issue
未关联
Pull Request 合并后将关闭上述关联 Issue
里程碑
未关联里程碑
参与者
(2)
1
https://gitee.com/mybatis-flex/mybatis-flex.git
git@gitee.com:mybatis-flex/mybatis-flex.git
mybatis-flex
mybatis-flex
MyBatis-Flex
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册