Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
life 2023-08-08 20:51:56 +08:00
commit ecd6ec879e
17 changed files with 983 additions and 627 deletions

View File

@ -84,6 +84,9 @@
- [MyBatis-Flex 视频教程 - 30 数据脱敏的简单使用](https://www.bilibili.com/video/BV1gz4y1s7Wg)
- [MyBatis-Flex 视频教程 - 31 枚举属性的使用](https://www.bilibili.com/video/BV1mm4y1W7SD)
- [MyBatis-Flex 视频教程 - 32 关联查询Join Query](https://www.bilibili.com/video/BV1B8411d7iC)
- [MyBatis-Flex 视频教程 - 33 关联查询Field Query](https://www.bilibili.com/video/BV17k4y1g7vt)
- [MyBatis-Flex 视频教程 - 34 关联查询Relation Query](https://www.bilibili.com/video/BV1bj411r7A4)
- [MyBatis-Flex 视频教程 - 35 关联查询对比](https://www.bilibili.com/video/BV1oF411f7dr)

View File

@ -87,14 +87,12 @@ MyBatis-Flex 已支持 Spring 框架的 `@Transactional`,在使用 SpringBoot
> 注意:若项目未使用 SpringBoot只用到了 Spring需要参考 MyBatis-Flex 的 [FlexTransactionAutoConfiguration](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/FlexTransactionAutoConfiguration.java)
> 进行事务配置,才能正常使用 `@Transactional` 注解。
## 特征
## 多数据源注意事项
- 1、支持嵌套事务
- 2、支持多数据源
注意在多数据源的情况下所有数据源的数据库请求Connection会执行相同的 `commit` 或者 `rollback`MyBatis-Flex 只保证了程序端的原子操作,
但并不能保证多个数据源之间的原子操作。例如:
> 注意在多数据源的情况下所有数据源的数据库请求Connection会执行相同的 commit 或者 rollback但并非原子操作。例如
```java
```java 1,6,13,19
@Transactional
public void doSomething(){
@ -117,7 +115,7 @@ public void doSomething(){
}
```
在以上的例子中,两次 `Db.update(...)` 虽然是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候,
在以上的例子中,执行了两次 `Db.updateBySql(...)`,它们是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候,
它们都会进行回滚rollback
以上提到的 `并非原子操作`,指的是:
@ -127,26 +125,112 @@ public void doSomething(){
## Seata 分布式事务
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
官方网站https://seata.io/zh-cn/index.html
1. 首先,先了解事务的基础(自行百度)
2. 在了解seata事务的项目 官网地址https://seata.io/zh-cn/docs
3. 然后根据官方的[快速开始](https://seata.io/zh-cn/docs/user/quickstart.html)在下载最新版的seata-server并在本地跑起一个
4. seata-server服务
5. 然后使用[mybatis-flex-test](https://gitee.com/mybatis-flex/mybatis-flex/tree/main/mybatis-flex-test)模块 下面的mybatis-flex-spring-boot-seata进行测试
>此demo只是一个纯演示的demo模仿的是[官方事例](https://github.com/seata/seata-samples/tree/master/springboot-mybatis)
进行整合微服务合并成一个多数据源进行测试当然这种方法是不提倡的seata事务并且本地多数据源的方式可能本身就存在设计思路问题可能存在过度设计此demo只是作为一个演示。
### 开始使用
**第 1 步:在 `application.yml` 配置开启 Seata 分布式事务功能:**
```yaml
mybatis-flex:
seata-config:
enable: true
seata-mode: XA # 支持 xa 或者 ta
```
- XA指的是: 分布式事务协议X/Open Distributed Transaction Processing它是一种由 X/Open 组织制定的分布式事务标准,
XA 使用两阶段提交2PCTwo-Phase Commit来保证所有资源同时提交或回滚任何特定的事务。
目前,几乎所有主流的数据库都对 XA 规范 提供了支持,是 Seata 默认使用的模式。
- AT 是一种无侵入的分布式事务解决方案。在 AT 模式下,用户只需关注自己的 “`业务SQL`”,
用户的 “`业务SQL`” 作为一阶段Seata 会根据 SQL 内容,自动生成事务的二阶段提交和回滚操作。
**第 2 步:在 `application.yml` 添加 Seata 的相关配置:**
```yaml
seata:
enabled: true
application-id: business-service
tx-service-group: my_test_tx_group
enable-auto-data-source-proxy: false #必须
# use-jdk-proxy: false
client:
rm:
async-commit-buffer-limit: 1000
report-retry-count: 5
table-meta-check-enable: false
report-success-enable: false
lock:
retry-interval: 10
retry-times: 30
retry-policy-branch-rollback-on-conflict: true
tm:
commit-retry-count: 5
rollback-retry-count: 5
undo:
data-validation: true
log-serialization: jackson
log-table: undo_log
log:
exceptionRate: 100
service:
vgroup-mapping:
my_test_tx_group: default
grouplist:
default: 127.0.0.1:8091
#enable-degrade: false
#disable-global-transaction: false
transport:
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
server-executor-thread-prefix: NettyServerBizHandler
share-boss-worker: false
client-selector-thread-prefix: NettyClientSelector
client-selector-thread-size: 1
client-worker-thread-prefix: NettyClientWorkerThread
worker-thread-size: default
boss-thread-size: 1
type: TCP
server: NIO
heartbeat: true
serialization: seata
compressor: none
enable-client-batch-send-request: true
config:
type: file
registry:
type: file
```
> 以上配置的含义,请参考 Seata 官方网站https://seata.io/zh-cn/docs/user/configurations.html
**3、通过使用 `@GloabalTransactional` 开始 Seata 分布式事务。**
```java 1
@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount) {
LOGGER.info("purchase begin ... xid: " + RootContext.getXID());
stockClient.deduct(commodityCode, orderCount);
orderClient.create(userId, commodityCode, orderCount);
}
```
> 更多关于 Seata 的知识,请异步 Seata 官方网站了解https://seata.io/zh-cn/docs ,也可以参考 Seata
> 的官方示例快速开始https://seata.io/zh-cn/docs/user/quickstart.html
### 注意事项
>使用seata的时候必须数据源代理
`seata.enable-auto-data-source-proxy: false`
`pom`自行引入[seata-spring-boot-starter](https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter)依赖,
在使用 Seata 分布式事务时,请注意添加 Seata 的相关 Maven 依赖,例如:
application.yml需要配置如下参数
1. `mybatis-flex.seata-config.enable`
配置含义seata事务是否开启true开启默认false关闭
2. `mybatis-flex.seata-config.seata-mode`
默认启动的事务类型目前只支持XA或者AT,默认AT
```xml
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
```

View File

@ -16,15 +16,15 @@
package com.mybatisflex.core.activerecord;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.activerecord.query.FieldsQuery;
import com.mybatisflex.core.activerecord.query.QueryModel;
import com.mybatisflex.core.activerecord.query.RelationsQuery;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.MapperQueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.SqlUtil;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
/**
* Active Record 模型
@ -36,7 +36,7 @@ import java.util.Optional;
@SuppressWarnings({"unused", "unchecked"})
public abstract class Model<T extends Model<T>>
extends QueryModel<T>
implements MapperModel<T>, Serializable {
implements MapperModel<T>, MapperQueryChain<T>, Serializable {
/**
* 根据实体类构建的条件删除数据
@ -66,175 +66,22 @@ public abstract class Model<T extends Model<T>>
return SqlUtil.toBool(baseMapper().updateByQuery((T) this, ignoreNulls, queryWrapper()));
}
/**
* 根据实体类构建的条件查询数据数量
*
* @return 数据数量
*/
public long count() {
return baseMapper().selectCountByQuery(queryWrapper());
@Override
public BaseMapper<T> baseMapper() {
return MapperModel.super.baseMapper();
}
/**
* 根据实体类构建的条件判断数据是否存在
*
* @return {@code true} 数据存在{@code false} 数据不存在
*/
public boolean exists() {
return SqlUtil.toBool(count());
@Override
public QueryWrapper toQueryWrapper() {
return queryWrapper();
}
/**
* 根据实体类构建的条件获取一条数据
*
* @return 数据
*/
public T one() {
return baseMapper().selectOneByQuery(queryWrapper());
}
/**
* 根据实体类构建的条件获取一条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @return 数据
*/
public <R> R oneAs(Class<R> asType) {
return baseMapper().selectOneByQueryAs(queryWrapper(), asType);
}
/**
* 根据实体类构建的条件获取一条数据并封装为 {@link Optional} 返回
*
* @return 数据
*/
public Optional<T> oneOpt() {
return Optional.ofNullable(one());
}
/**
* 根据实体类构建的条件获取一条数据返回的数据为 asType 类型并封装为 {@link Optional} 返回
*
* @param asType 接收数据类型
* @return 数据
*/
public <R> Optional<R> oneAsOpt(Class<R> asType) {
return Optional.ofNullable(oneAs(asType));
}
/**
* 根据实体类构建的条件获取第一列且第一条数据
*
* @return 第一列数据
*/
public Object obj() {
return baseMapper().selectObjectByQuery(queryWrapper());
}
/**
* 根据实体类构建的条件获取第一列且第一条数据并转换为指定类型比如 {@code Long}, {@code String}
*
* @param asType 接收数据类型
* @return 第一列数据
*/
public <R> R objAs(Class<R> asType) {
return baseMapper().selectObjectByQueryAs(queryWrapper(), asType);
}
/**
* 根据实体类构建的条件获取第一列且第一条数据并封装为 {@link Optional} 返回
*
* @return 第一列数据
*/
public Optional<Object> objOpt() {
return Optional.ofNullable(obj());
}
/**
* 根据实体类构建的条件获取第一列且第一条数据并转换为指定类型比如 {@code Long}, {@code String}
* 封装为 {@link Optional} 返回
*
* @param asType 接收数据类型
* @return 第一列数据
*/
public <R> Optional<R> objAsOpt(Class<R> asType) {
return Optional.ofNullable(objAs(asType));
}
/**
* 根据实体类构建的条件获取第一列的所有数据
*
* @return 第一列数据
*/
public List<Object> objList() {
return baseMapper().selectObjectListByQuery(queryWrapper());
}
/**
* 根据实体类构建的条件获取第一列的所有数据并转换为指定类型比如 {@code Long}, {@code String}
*
* @param asType 接收数据类型
* @return 第一列数据
*/
public <R> List<R> objListAs(Class<R> asType) {
return baseMapper().selectObjectListByQueryAs(queryWrapper(), asType);
}
/**
* 根据实体类构建的条件获取多条数据
*
* @return 数据列表
*/
public List<T> list() {
return baseMapper().selectListByQuery(queryWrapper());
}
/**
* 根据实体类构建的条件获取多条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @return 数据列表
*/
public <R> List<R> listAs(Class<R> asType) {
return baseMapper().selectListByQueryAs(queryWrapper(), asType);
}
/**
* 根据实体类构建的条件获取分页数据
*
* @param page 分页对象
* @return 分页数据
*/
public Page<T> page(Page<T> page) {
return baseMapper().paginate(page, queryWrapper());
}
/**
* 根据实体类构建的条件获取分页数据返回的数据为 asType 类型
*
* @param page 分页对象
* @param asType 接收数据类型
* @return 分页数据
*/
public <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
return baseMapper().paginateAs(page, queryWrapper(), asType);
}
/**
* 使用 {@code Fields Query} 的方式进行关联查询
*
* @return {@code Fields Query} 查询
*/
@Override
public FieldsQuery<T> withFields() {
return new FieldsQuery<>(this);
}
/**
* 使用 {@code Relations Query} 的方式进行关联查询
*
* @return {@code Relations Query} 查询
*/
@Override
public RelationsQuery<T> withRelations() {
return new RelationsQuery<>(this);
}

View File

@ -1,160 +0,0 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.activerecord.query;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.activerecord.Model;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.List;
import java.util.Optional;
/**
* 抽象关联查询
*
* @author 王帅
* @since 2023-07-30
*/
public abstract class AbstractQuery<T extends Model<T>> {
protected final Model<T> model;
protected AbstractQuery(Model<T> model) {
this.model = model;
}
/**
* @return 主键
*/
protected Object[] pkValues() {
return model.pkValues();
}
/**
* @return BaseMapper
*/
protected BaseMapper<T> baseMapper() {
return model.baseMapper();
}
/**
* @return QueryWrapper
*/
protected QueryWrapper queryWrapper() {
return model.queryWrapper();
}
/**
* 根据实体类主键获取一条数据
*
* @return 数据
*/
public abstract T oneById();
/**
* 根据实体类主键获取一条数据并封装为 {@link Optional} 返回
*
* @return 数据
*/
public Optional<T> oneByIdOpt() {
return Optional.ofNullable(oneById());
}
/**
* 根据实体类主键获取一条数据
*
* @return 数据
*/
public abstract <R> R oneByIdAs(Class<R> asType);
/**
* 根据实体类主键获取一条数据并封装为 {@link Optional} 返回
*
* @return 数据
*/
public <R> Optional<R> oneByIdAsOpt(Class<R> asType) {
return Optional.ofNullable(oneByIdAs(asType));
}
/**
* 根据实体类构建的条件获取一条数据
*
* @return 数据
*/
public abstract T one();
/**
* 根据实体类构建的条件获取一条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @return 数据
*/
public abstract <R> R oneAs(Class<R> asType);
/**
* 根据实体类构建的条件获取一条数据并封装为 {@link Optional} 返回
*
* @return 数据
*/
public Optional<T> oneOpt() {
return Optional.ofNullable(one());
}
/**
* 根据实体类构建的条件获取一条数据返回的数据为 asType 类型并封装为 {@link Optional} 返回
*
* @param asType 接收数据类型
* @return 数据
*/
public <R> Optional<R> oneOptAs(Class<R> asType) {
return Optional.ofNullable(oneAs(asType));
}
/**
* 根据实体类构建的条件获取多条数据
*
* @return 数据列表
*/
public abstract List<T> list();
/**
* 根据实体类构建的条件获取多条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @return 数据列表
*/
public abstract <R> List<R> listAs(Class<R> asType);
/**
* 根据实体类构建的条件获取分页数据
*
* @param page 分页对象
* @return 分页数据
*/
public abstract Page<T> page(Page<T> page);
/**
* 根据实体类构建的条件获取分页数据返回的数据为 asType 类型
*
* @param page 分页对象
* @param asType 接收数据类型
* @return 分页数据
*/
public abstract <R> Page<R> pageAs(Page<R> page, Class<R> asType);
}

View File

@ -17,19 +17,14 @@
package com.mybatisflex.core.activerecord.query;
import com.mybatisflex.core.activerecord.Model;
import com.mybatisflex.core.field.FieldQuery;
import com.mybatisflex.core.field.FieldQueryManager;
import com.mybatisflex.core.field.QueryBuilder;
import com.mybatisflex.core.mybatis.MappedStatementTypes;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.util.FieldWrapper;
import com.mybatisflex.core.query.FieldsBuilder;
import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 使用 {@code Fields Query} 的方式进行关联查询
@ -37,53 +32,34 @@ import java.util.Map;
* @author 王帅
* @since 2023-07-30
*/
public class FieldsQuery<T extends Model<T>> extends AbstractQuery<T> {
private final Map<String, FieldQuery> fieldQueryMap;
public class FieldsQuery<T extends Model<T>> extends FieldsBuilder<T> {
public FieldsQuery(Model<T> model) {
super(model);
this.fieldQueryMap = new HashMap<>();
}
/**
* 设置属性对应的 {@code QueryWrapper} 查询
*
* @param field 属性
* @param builder {@code QueryWrapper} 构建
* @param <F> 属性类型
* @return 属性查询构建
*/
@Override
public <F> FieldsQuery<T> fieldMapping(LambdaGetter<F> field, QueryBuilder<F> builder) {
return fieldMapping(field, false, builder);
}
/**
* 设置属性对应的 {@code QueryWrapper} 查询
*
* @param field 属性
* @param prevent 阻止对嵌套类属性的查询
* @param builder {@code QueryWrapper} 构建
* @param <F> 属性类型
* @return 属性查询构建
*/
public <F> FieldsQuery<T> fieldMapping(LambdaGetter<F> field, boolean prevent, QueryBuilder<F> builder) {
String fieldName = LambdaUtil.getFieldName(field);
Class<?> entityClass = LambdaUtil.getImplClass(field);
FieldQuery fieldQuery = new FieldQuery();
fieldQuery.setPrevent(prevent);
fieldQuery.setFieldName(fieldName);
fieldQuery.setQueryBuilder(builder);
fieldQuery.setEntityClass(entityClass);
fieldQuery.setFieldWrapper(FieldWrapper.of(entityClass, fieldName));
this.fieldQueryMap.put(entityClass.getName() + '#' + fieldName, fieldQuery);
super.fieldMapping(field, builder);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public <F> FieldsBuilder<T> fieldMapping(LambdaGetter<F> field, boolean prevent, QueryBuilder<F> builder) {
super.fieldMapping(field, prevent, builder);
return this;
}
protected Object[] pkValues() {
// 懒加载实际用到的时候才会生成 主键值
return ((Model<T>) delegate).pkValues();
}
/**
* 根据主键查询一条数据
*
* @return 一条数据
*/
public T oneById() {
List<T> entities = Collections.singletonList(baseMapper().selectOneById(pkValues()));
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
@ -91,9 +67,12 @@ public class FieldsQuery<T extends Model<T>> extends AbstractQuery<T> {
}
/**
* {@inheritDoc}
* 根据主键查询一条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 一条数据
*/
@Override
@SuppressWarnings("unchecked")
public <R> R oneByIdAs(Class<R> asType) {
try {
@ -106,64 +85,4 @@ public class FieldsQuery<T extends Model<T>> extends AbstractQuery<T> {
}
}
/**
* {@inheritDoc}
*/
@Override
public T one() {
List<T> entities = Collections.singletonList(baseMapper().selectOneByQuery(queryWrapper()));
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public <R> R oneAs(Class<R> asType) {
List<R> entities = Collections.singletonList(baseMapper().selectOneByQueryAs(queryWrapper(), asType));
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public List<T> list() {
List<T> entities = baseMapper().selectListByQuery(queryWrapper());
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities;
}
/**
* {@inheritDoc}
*/
@Override
public <R> List<R> listAs(Class<R> asType) {
List<R> entities = baseMapper().selectListByQueryAs(queryWrapper(), asType);
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities;
}
/**
* {@inheritDoc}
*/
@Override
public Page<T> page(Page<T> page) {
baseMapper().paginate(page, queryWrapper());
FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap);
return page;
}
/**
* {@inheritDoc}
*/
@Override
public <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
baseMapper().paginateAs(page, queryWrapper(), asType);
FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap);
return page;
}
}

View File

@ -17,10 +17,8 @@
package com.mybatisflex.core.activerecord.query;
import com.mybatisflex.core.activerecord.Model;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.relation.RelationManager;
import java.util.List;
import com.mybatisflex.core.query.RelationsBuilder;
import com.mybatisflex.core.util.LambdaGetter;
/**
* 使用 {@code Relations Query} 的方式进行关联查询
@ -28,102 +26,59 @@ import java.util.List;
* @author 王帅
* @since 2023-07-30
*/
public class RelationsQuery<T extends Model<T>> extends AbstractQuery<T> {
public class RelationsQuery<T extends Model<T>> extends RelationsBuilder<T> {
public RelationsQuery(Model<T> model) {
super(model);
}
/**
* 忽略查询部分 {@code Relations} 注解标记的属性
*
* @param fields 属性
* @return {@code Relations} 查询构建
*/
@Override
public RelationsQuery<T> ignoreRelations(String... fields) {
RelationManager.addIgnoreRelations(fields);
return this;
}
/**
* 设置父子关系查询中默认的递归查询深度
*
* @param maxDepth 查询深度
* @return {@code Relations} 查询构建
*/
public RelationsQuery<T> maxDepth(int maxDepth) {
RelationManager.setMaxDepth(maxDepth);
return this;
}
/**
* 添加额外的 {@code Relations} 查询条件
*
* @param key
* @param value
* @return {@code Relations} 查询构建
*/
public RelationsQuery<T> extraConditionParam(String key, Object value) {
RelationManager.addExtraConditionParam(key, value);
super.ignoreRelations(fields);
return this;
}
@Override
public RelationsQuery<T> ignoreRelations(LambdaGetter<T>... fields) {
super.ignoreRelations(fields);
return this;
}
@Override
public RelationsQuery<T> maxDepth(int maxDepth) {
super.maxDepth(maxDepth);
return this;
}
@Override
public RelationsQuery<T> extraConditionParam(String key, Object value) {
super.extraConditionParam(key, value);
return this;
}
protected Object[] pkValues() {
// 懒加载实际用到的时候才会生成 主键值
return ((Model<T>) delegate).pkValues();
}
/**
* 根据主键查询一条数据
*
* @return 一条数据
*/
public T oneById() {
return baseMapper().selectOneWithRelationsById(pkValues());
}
@Override
/**
* 根据主键查询一条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 一条数据
*/
public <R> R oneByIdAs(Class<R> asType) {
return baseMapper().selectOneWithRelationsByIdAs(pkValues(), asType);
}
/**
* {@inheritDoc}
*/
@Override
public T one() {
return baseMapper().selectOneWithRelationsByQuery(queryWrapper());
}
/**
* {@inheritDoc}
*/
@Override
public <R> R oneAs(Class<R> asType) {
return baseMapper().selectOneWithRelationsByQueryAs(queryWrapper(), asType);
}
/**
* {@inheritDoc}
*/
@Override
public List<T> list() {
return baseMapper().selectListWithRelationsByQuery(queryWrapper());
}
/**
* {@inheritDoc}
*/
@Override
public <R> List<R> listAs(Class<R> asType) {
return baseMapper().selectListWithRelationsByQueryAs(queryWrapper(), asType);
}
/**
* {@inheritDoc}
*/
@Override
public Page<T> page(Page<T> page) {
return baseMapper().paginateWithRelations(page, queryWrapper());
}
/**
* {@inheritDoc}
*/
@Override
public <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
return baseMapper().paginateWithRelationsAs(page, queryWrapper(), asType);
}
}

View File

@ -21,6 +21,9 @@ import org.apache.ibatis.logging.LogFactory;
import javax.sql.DataSource;
import java.lang.reflect.Method;
/**
* @author michael
*/
public class DataSourceManager {
private static DataSourceDecipher decipher;

View File

@ -49,8 +49,13 @@ public class FlexDataSource extends AbstractDataSource {
private final DataSource defaultDataSource;
public FlexDataSource(String dataSourceKey, DataSource dataSource) {
this(dataSourceKey, dataSource, true);
}
DataSourceManager.decryptDataSource(dataSource);
public FlexDataSource(String dataSourceKey, DataSource dataSource, boolean needDecryptDataSource) {
if (needDecryptDataSource) {
DataSourceManager.decryptDataSource(dataSource);
}
this.defaultDataSourceKey = dataSourceKey;
this.defaultDataSource = dataSource;
@ -61,11 +66,19 @@ public class FlexDataSource extends AbstractDataSource {
}
public void addDataSource(String dataSourceKey, DataSource dataSource) {
DataSourceManager.decryptDataSource(dataSource);
addDataSource(dataSourceKey, dataSource, true);
}
public void addDataSource(String dataSourceKey, DataSource dataSource, boolean needDecryptDataSource) {
if (needDecryptDataSource) {
DataSourceManager.decryptDataSource(dataSource);
}
dataSourceMap.put(dataSourceKey, dataSource);
dbTypeHashMap.put(dataSourceKey, DbTypeUtil.getDbType(dataSource));
}
public void removeDatasource(String dataSourceKey) {
dataSourceMap.remove(dataSourceKey);
dbTypeHashMap.remove(dataSourceKey);

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.query;
import com.mybatisflex.core.BaseMapper;
/**
* 抽象关联查询
*
* @author 王帅
* @since 2023-08-08
*/
public abstract class AbstractQueryBuilder<T> implements ChainQuery<T> {
protected final MapperQueryChain<T> delegate;
protected AbstractQueryBuilder(MapperQueryChain<T> delegate) {
this.delegate = delegate;
}
/**
* @return BaseMapper
*/
protected BaseMapper<T> baseMapper() {
return delegate.baseMapper();
}
/**
* @return QueryWrapper
*/
protected QueryWrapper queryWrapper() {
return delegate.toQueryWrapper();
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.query;
import com.mybatisflex.core.paginate.Page;
import java.util.List;
import java.util.Optional;
/**
* <p>链式查询接口
*
* <p>该接口定义了通用的链式查询方法
* <ul>
* <li><b>one</b>: 查询一条数据
* <li><b>list</b>: 查询多条数据
* <li><b>page</b>: 分页查询数据
* </ul>
*
* @param <T> 实体类类型
* @author 王帅
* @since 2023-08-08
*/
public interface ChainQuery<T> {
/**
* 获取一条数据
*
* @return 一条数据
*/
T one();
/**
* 获取一条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 一条数据
*/
<R> R oneAs(Class<R> asType);
/**
* 获取一条数据并封装为 {@link Optional} 返回
*
* @return 一条数据
*/
default Optional<T> oneOpt() {
return Optional.ofNullable(one());
}
/**
* 获取一条数据返回的数据为 asType 类型并封装为 {@link Optional} 返回
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 一条数据
*/
default <R> Optional<R> oneAsOpt(Class<R> asType) {
return Optional.ofNullable(oneAs(asType));
}
/**
* 获取多条数据
*
* @return 数据列表
*/
List<T> list();
/**
* 获取多条数据返回的数据为 asType 类型
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 数据列表
*/
<R> List<R> listAs(Class<R> asType);
/**
* 获取分页数据
*
* @param page 分页对象
* @return 分页数据
*/
Page<T> page(Page<T> page);
/**
* 获取分页数据返回的数据为 asType 类型
*
* @param page 分页对象
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 分页数据
*/
<R> Page<R> pageAs(Page<R> page, Class<R> asType);
}

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.query;
import com.mybatisflex.core.field.FieldQuery;
import com.mybatisflex.core.field.FieldQueryManager;
import com.mybatisflex.core.field.QueryBuilder;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.util.FieldWrapper;
import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 使用 {@code Fields Query} 的方式进行关联查询
*
* @author 王帅
* @since 2023-08-08
*/
public class FieldsBuilder<T> extends AbstractQueryBuilder<T> {
protected final Map<String, FieldQuery> fieldQueryMap;
public FieldsBuilder(MapperQueryChain<T> delegate) {
super(delegate);
this.fieldQueryMap = new HashMap<>();
}
/**
* 设置属性对应的 {@code QueryWrapper} 查询
*
* @param field 属性
* @param builder {@code QueryWrapper} 构建
* @param <F> 属性类型
* @return 属性查询构建
*/
public <F> FieldsBuilder<T> fieldMapping(LambdaGetter<F> field, QueryBuilder<F> builder) {
return fieldMapping(field, false, builder);
}
/**
* 设置属性对应的 {@code QueryWrapper} 查询
*
* @param field 属性
* @param prevent 阻止对嵌套类属性的查询
* @param builder {@code QueryWrapper} 构建
* @param <F> 属性类型
* @return 属性查询构建
*/
public <F> FieldsBuilder<T> fieldMapping(LambdaGetter<F> field, boolean prevent, QueryBuilder<F> builder) {
String fieldName = LambdaUtil.getFieldName(field);
Class<?> entityClass = LambdaUtil.getImplClass(field);
FieldQuery fieldQuery = new FieldQuery();
fieldQuery.setPrevent(prevent);
fieldQuery.setFieldName(fieldName);
fieldQuery.setQueryBuilder(builder);
fieldQuery.setEntityClass(entityClass);
fieldQuery.setFieldWrapper(FieldWrapper.of(entityClass, fieldName));
this.fieldQueryMap.put(entityClass.getName() + '#' + fieldName, fieldQuery);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public T one() {
List<T> entities = Collections.singletonList(baseMapper().selectOneByQuery(queryWrapper()));
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public <R> R oneAs(Class<R> asType) {
List<R> entities = Collections.singletonList(baseMapper().selectOneByQueryAs(queryWrapper(), asType));
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public List<T> list() {
List<T> entities = baseMapper().selectListByQuery(queryWrapper());
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities;
}
/**
* {@inheritDoc}
*/
@Override
public <R> List<R> listAs(Class<R> asType) {
List<R> entities = baseMapper().selectListByQueryAs(queryWrapper(), asType);
FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap);
return entities;
}
/**
* {@inheritDoc}
*/
@Override
public Page<T> page(Page<T> page) {
baseMapper().paginate(page, queryWrapper());
FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap);
return page;
}
/**
* {@inheritDoc}
*/
@Override
public <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
baseMapper().paginateAs(page, queryWrapper(), asType);
FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap);
return page;
}
}

View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.query;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.util.SqlUtil;
import java.util.List;
import java.util.Optional;
/**
* <p>链式 {@link BaseMapper} 查询
*
* <p>要求实现类除了包含有 {@link BaseMapper} 接口的引用外还必须具有 {@link QueryWrapper}
* 的查询条件构建功能在使用时
* <ul>
* <li>通过 {@link #baseMapper()} 获取该实现类对应的 {@link BaseMapper} 引用
* <li>通过 {@link #toQueryWrapper()} 将该实现类转换为 {@link QueryWrapper} 对象
* </ul>
*
* @param <T> 实体类类型
* @author 王帅
* @since 2023-08-08
*/
public interface MapperQueryChain<T> extends ChainQuery<T> {
/**
* 该实现类对应的 {@link BaseMapper} 对象
*
* @return {@link BaseMapper}
*/
BaseMapper<T> baseMapper();
/**
* 将该实现类转换为 {@link QueryWrapper} 对象
*
* @return {@link QueryWrapper}
*/
QueryWrapper toQueryWrapper();
/**
* 查询数据数量
*
* @return 数据数量
*/
default long count() {
return baseMapper().selectCountByQuery(toQueryWrapper());
}
/**
* 判断数据是否存在
*
* @return {@code true} 数据存在{@code false} 数据不存在
*/
default boolean exists() {
return SqlUtil.toBool(count());
}
/**
* {@inheritDoc}
*/
default T one() {
return baseMapper().selectOneByQuery(toQueryWrapper());
}
/**
* {@inheritDoc}
*/
default <R> R oneAs(Class<R> asType) {
return baseMapper().selectOneByQueryAs(toQueryWrapper(), asType);
}
/**
* 获取第一列且第一条数据
*
* @return 第一列数据
*/
default Object obj() {
return baseMapper().selectObjectByQuery(toQueryWrapper());
}
/**
* 获取第一列且第一条数据并转换为指定类型比如 {@code Long}, {@code String}
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 第一列数据
*/
default <R> R objAs(Class<R> asType) {
return baseMapper().selectObjectByQueryAs(toQueryWrapper(), asType);
}
/**
* 获取第一列且第一条数据并封装为 {@link Optional} 返回
*
* @return 第一列数据
*/
default Optional<Object> objOpt() {
return Optional.ofNullable(obj());
}
/**
* 获取第一列且第一条数据并转换为指定类型比如 {@code Long}, {@code String}
* 封装为 {@link Optional} 返回
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 第一列数据
*/
default <R> Optional<R> objAsOpt(Class<R> asType) {
return Optional.ofNullable(objAs(asType));
}
/**
* 获取第一列的所有数据
*
* @return 第一列数据
*/
default List<Object> objList() {
return baseMapper().selectObjectListByQuery(toQueryWrapper());
}
/**
* 获取第一列的所有数据并转换为指定类型比如 {@code Long}, {@code String}
*
* @param asType 接收数据类型
* @param <R> 接收数据类型
* @return 第一列数据
*/
default <R> List<R> objListAs(Class<R> asType) {
return baseMapper().selectObjectListByQueryAs(toQueryWrapper(), asType);
}
/**
* {@inheritDoc}
*/
default List<T> list() {
return baseMapper().selectListByQuery(toQueryWrapper());
}
/**
* {@inheritDoc}
*/
default <R> List<R> listAs(Class<R> asType) {
return baseMapper().selectListByQueryAs(toQueryWrapper(), asType);
}
/**
* {@inheritDoc}
*/
default Page<T> page(Page<T> page) {
return baseMapper().paginate(page, toQueryWrapper());
}
/**
* {@inheritDoc}
*/
default <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
return baseMapper().paginateAs(page, toQueryWrapper(), asType);
}
/**
* 使用 {@code Fields Query} 的方式进行关联查询
*
* @return {@code Fields Query} 查询
*/
default FieldsBuilder<T> withFields() {
return new FieldsBuilder<>(this);
}
/**
* 使用 {@code Relations Query} 的方式进行关联查询
*
* @return {@code Relations Query} 查询
*/
default RelationsBuilder<T> withRelations() {
return new RelationsBuilder<>(this);
}
}

View File

@ -20,18 +20,17 @@ import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.table.TableInfo;
import com.mybatisflex.core.table.TableInfoFactory;
import com.mybatisflex.core.util.SqlUtil;
import java.util.List;
import java.util.Optional;
/**
* {@link QueryWrapper}链式调用
* {@link QueryWrapper} 链式调用
*
* @author 王帅
* @since 2023-07-22
*/
public class QueryChain<T> extends QueryWrapperAdapter<QueryChain<T>> {
public class QueryChain<T> extends QueryWrapperAdapter<QueryChain<T>> implements MapperQueryChain<T> {
private final BaseMapper<T> baseMapper;
@ -43,98 +42,76 @@ public class QueryChain<T> extends QueryWrapperAdapter<QueryChain<T>> {
return new QueryChain<>(baseMapper);
}
public long count() {
return baseMapper.selectCountByQuery(this);
@Override
public BaseMapper<T> baseMapper() {
return baseMapper;
}
public boolean exists() {
return SqlUtil.toBool(count());
}
public T one() {
return baseMapper.selectOneByQuery(this);
}
public <R> R oneAs(Class<R> asType) {
return baseMapper.selectOneByQueryAs(this, asType);
@Override
public QueryWrapper toQueryWrapper() {
return this;
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public T oneWithRelations() {
return baseMapper.selectOneWithRelationsByQuery(this);
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public <R> R oneWithRelationsAs(Class<R> asType) {
return baseMapper.selectOneWithRelationsByQueryAs(this, asType);
}
public Optional<T> oneOpt() {
return Optional.ofNullable(baseMapper.selectOneByQuery(this));
}
public <R> Optional<R> oneAsOpt(Class<R> asType) {
return Optional.ofNullable(baseMapper.selectOneByQueryAs(this, asType));
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public Optional<T> oneWithRelationsOpt() {
return Optional.ofNullable(baseMapper.selectOneWithRelationsByQuery(this));
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public <R> Optional<R> oneWithRelationsAsOpt(Class<R> asType) {
return Optional.ofNullable(baseMapper.selectOneWithRelationsByQueryAs(this, asType));
}
public Object obj() {
return baseMapper.selectObjectByQuery(this);
}
public <R> R objAs(Class<R> asType) {
return baseMapper.selectObjectByQueryAs(this, asType);
}
public Optional<Object> objOpt() {
return Optional.ofNullable(baseMapper.selectObjectByQuery(this));
}
public <R> Optional<R> objAsOpt(Class<R> asType) {
return Optional.ofNullable(baseMapper.selectObjectByQueryAs(this, asType));
}
public List<Object> objList() {
return baseMapper.selectObjectListByQuery(this);
}
public <R> List<R> objListAs(Class<R> asType) {
return baseMapper.selectObjectListByQueryAs(this, asType);
}
public List<T> list() {
return baseMapper.selectListByQuery(this);
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public List<T> listWithRelations() {
return baseMapper.selectListWithRelationsByQuery(this);
}
public <R> List<R> listAs(Class<R> asType) {
return baseMapper.selectListByQueryAs(this, asType);
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public <R> List<R> listWithRelationsAs(Class<R> asType) {
return baseMapper.selectListWithRelationsByQueryAs(this, asType);
}
public Page<T> page(Page<T> page) {
return baseMapper.paginate(page, this);
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public Page<T> pageWithRelations(Page<T> page) {
return baseMapper.paginateWithRelations(page, this);
}
public <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
return baseMapper.paginateAs(page, this, asType);
}
/**
* @deprecated 该方法将在 1.6.0 版本移除
*/
@Deprecated
public <R> Page<R> pageWithRelationsAs(Page<R> page, Class<R> asType) {
return baseMapper.paginateWithRelationsAs(page, this, asType);
}
@ -145,4 +122,5 @@ public class QueryChain<T> extends QueryWrapperAdapter<QueryChain<T>> {
CPI.setFromIfNecessary(this, tableInfo.getSchema(), tableInfo.getTableName());
return super.toSQL();
}
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.query;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.relation.RelationManager;
import com.mybatisflex.core.util.LambdaGetter;
import java.util.List;
/**
* 使用 {@code Relations Query} 的方式进行关联查询
*
* @author 王帅
* @since 2023-08-08
*/
public class RelationsBuilder<T> extends AbstractQueryBuilder<T> {
public RelationsBuilder(MapperQueryChain<T> delegate) {
super(delegate);
}
/**
* 忽略查询部分 {@code Relations} 注解标记的属性
*
* @param fields 属性
* @return {@code Relations} 查询构建
*/
public RelationsBuilder<T> ignoreRelations(String... fields) {
RelationManager.addIgnoreRelations(fields);
return this;
}
/**
* 忽略查询部分 {@code Relations} 注解标记的属性
*
* @param fields 属性
* @return {@code Relations} 查询构建
*/
public RelationsBuilder<T> ignoreRelations(LambdaGetter<T>... fields) {
RelationManager.addIgnoreRelations(fields);
return this;
}
/**
* 设置父子关系查询中默认的递归查询深度
*
* @param maxDepth 查询深度
* @return {@code Relations} 查询构建
*/
public RelationsBuilder<T> maxDepth(int maxDepth) {
RelationManager.setMaxDepth(maxDepth);
return this;
}
/**
* 添加额外的 {@code Relations} 查询条件
*
* @param key
* @param value
* @return {@code Relations} 查询构建
*/
public RelationsBuilder<T> extraConditionParam(String key, Object value) {
RelationManager.addExtraConditionParam(key, value);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public T one() {
return baseMapper().selectOneWithRelationsByQuery(queryWrapper());
}
/**
* {@inheritDoc}
*/
@Override
public <R> R oneAs(Class<R> asType) {
return baseMapper().selectOneWithRelationsByQueryAs(queryWrapper(), asType);
}
/**
* {@inheritDoc}
*/
@Override
public List<T> list() {
return baseMapper().selectListWithRelationsByQuery(queryWrapper());
}
/**
* {@inheritDoc}
*/
@Override
public <R> List<R> listAs(Class<R> asType) {
return baseMapper().selectListWithRelationsByQueryAs(queryWrapper(), asType);
}
/**
* {@inheritDoc}
*/
@Override
public Page<T> page(Page<T> page) {
return baseMapper().paginateWithRelations(page, queryWrapper());
}
/**
* {@inheritDoc}
*/
@Override
public <R> Page<R> pageAs(Page<R> page, Class<R> asType) {
return baseMapper().paginateWithRelationsAs(page, queryWrapper(), asType);
}
}

View File

@ -81,18 +81,22 @@ public class MultiDataSourceAutoConfiguration {
DataSourceManager.setDecipher(dataSourceDecipher);
for (Map.Entry<String, Map<String, String>> entry : dataSourceProperties.entrySet()) {
DataSource dataSource = new DataSourceBuilder(entry.getValue()).build();
if (seataConfig !=null &&seataConfig.isEnable()){
if (seataConfig.getSeataMode() ==SeataMode.XA){
DataSourceManager.decryptDataSource(dataSource);
if (seataConfig != null && seataConfig.isEnable()) {
if (seataConfig.getSeataMode() == SeataMode.XA) {
dataSource = new DataSourceProxyXA(dataSource);
}else {
} else {
dataSource = new DataSourceProxy(dataSource);
}
}
if (flexDataSource == null) {
flexDataSource = new FlexDataSource(entry.getKey(), dataSource);
flexDataSource = new FlexDataSource(entry.getKey(), dataSource, false);
} else {
flexDataSource.addDataSource(entry.getKey(), dataSource);
flexDataSource.addDataSource(entry.getKey(), dataSource, false);
}
}
}

View File

@ -3,20 +3,20 @@ spring:
# h2:
# console:
# enabled: true
# datasource:
## driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/flex_test
# username: root
# password: 131496
datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/flex_test
username: root
password: 12345678
# driver-class-name:
# datasource:
# driver-class-name: org.h2.Driver
# username: root
# password: test
sql:
init:
schema-locations: classpath:schema.sql
data-locations: classpath:data.sql
# sql:
# init:
# schema-locations: classpath:schema.sql
# data-locations: classpath:data.sql
mybatis-flex:
admin-config:
enable: true
@ -37,12 +37,12 @@ mybatis-flex:
# username: root
# password: 12345678
#mybatis-flex:
datasource:
ds3333:
url: jdbc:mysql://127.0.0.1:3306/flex_test
username: root
password: 131496
ds2:
url: jdbc:mysql://127.0.0.1:3306/flex_test1
username: root
password: 131496
# datasource:
# ds3333:
# url: jdbc:mysql://127.0.0.1:3306/flex_test
# username: root
# password: 131496
# ds2:
# url: jdbc:mysql://127.0.0.1:3306/flex_test1
# username: root
# password: 131496

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.test.mapper;
import com.mybatisflex.core.field.QueryBuilder;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.test.model.User;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static com.mybatisflex.test.model.table.RoleTableDef.ROLE;
import static com.mybatisflex.test.model.table.UserRoleTableDef.USER_ROLE;
import static com.mybatisflex.test.model.table.UserTableDef.USER;
/**
* @author 王帅
* @since 2023-08-08
*/
@SpringBootTest
class QueryChainTest {
@Autowired
UserMapper userMapper;
@Test
void testFields() {
QueryBuilder<User> builder = user ->
QueryWrapper.create()
.select()
.from(ROLE)
.where(ROLE.ROLE_ID.in(
QueryWrapper.create()
.select(USER_ROLE.ROLE_ID)
.from(USER_ROLE)
.where(USER_ROLE.USER_ID.eq(user.getUserId()))
));
User user1 = QueryChain.of(userMapper)
.where(USER.USER_ID.eq(1))
.withFields()
.fieldMapping(User::getRoleList, builder)
.one();
User user2 = User.create()
.where(USER.USER_ID.eq(1))
.withFields()
.fieldMapping(User::getRoleList, builder)
.one();
Assertions.assertEquals(user1.toString(), user2.toString());
}
@Test
void testRelations() {
User user1 = QueryChain.of(userMapper)
.where(USER.USER_ID.eq(2))
.withRelations()
.one();
User user2 = User.create()
.where(USER.USER_ID.eq(2))
.withRelations()
.one();
Assertions.assertEquals(user1.toString(), user2.toString());
}
}