mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 17:18:24 +08:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
d7bdc2aea0
@ -20,7 +20,7 @@ features:
|
||||
- title: 更轻量
|
||||
details: MyBatis-Flex 除了 MyBatis 本身,再无任何第三方依赖,因此会带来更高的自主性、把控性和稳定性。在任何一个系统中,依赖越多,稳定性越差。
|
||||
- title: 更灵活
|
||||
details: MyBatis-Flex 提供了非常灵活的 QueryWrapper,支持关联查询、多表查询、多主键、逻辑删除、乐观锁更新、数据填充、数据脱敏、等等....
|
||||
details: MyBatis-Flex 提供了非常灵活的 QueryWrapper,支持关联查询、多表查询、多主键、逻辑删除、乐观锁更新、数据填充、数据脱敏等等。
|
||||
- title: 更高的性能
|
||||
details: MyBatis-Flex 通过独特的架构,没有任何 MyBatis 拦截器、在 SQL 执行的过程中,没有任何的 SQL Parse,因此会带来指数级的性能增长。
|
||||
---
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1017,6 +1017,64 @@ QueryWrapper query2 = QueryWrapper.create()
|
||||
在以上的 `query1` 中,由于 `userName` 和 `id` 都为 null,MyBatis-Flex 会自动忽略 null 值的条件,因此,它们构建出来的 SQL 条件是和 `query2` 完全一致的 。
|
||||
|
||||
|
||||
## QueryColumnBehavior <Badge type="tip" text="^ v1.5.6" />
|
||||
|
||||
在以上的内容中,我们知道 MyBatis-Flex 会自动忽略 `null` 值的条件,但是在实际开发中,有的开发者希望除了自动忽略 `null`
|
||||
值以外,还可以自动忽略其他值,比如 `空字符串` 等。
|
||||
|
||||
|
||||
此时,我们可以通过配置 QueryColumnBehavior 来自定义忽略的值。如下的代码会自动忽略 `null` 和 `空字符串`:
|
||||
|
||||
```java
|
||||
QueryColumnBehavior.setIgnoreFunction(new Predicate<Object>() {
|
||||
@Override
|
||||
public boolean test(Object o) {
|
||||
return "".equals(o);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
另外,在某些场景下,开发者希望在构建 QueryWrapper 中,如果传入的值是集合或数组,则使用 `in` 逻辑,否则使用 `=`(等于)
|
||||
逻辑:
|
||||
|
||||
```java
|
||||
QueryColumnBehavior.setSmartConvertInToEquals(true);
|
||||
```
|
||||
|
||||
当添加以上配置时,我们在构建 QueryWrapper 的 `in` 的 SQL 时,逻辑如下:
|
||||
|
||||
```java
|
||||
// ids 有多个值
|
||||
List<Integer> ids = Arrays.asList(1, 2, 3);
|
||||
QueryWrapper qw = new QueryWrapper();
|
||||
qw.where(ACCOUNT.ID.in(ids))
|
||||
|
||||
System.out.println(qw.toSQL());
|
||||
```
|
||||
输出的 SQL 如下:
|
||||
|
||||
```sql
|
||||
select * from tb_account where id in (1,2,3);
|
||||
```
|
||||
|
||||
若 `ids` 只有 1 个值时,逻辑如下:
|
||||
|
||||
```java
|
||||
// ids 只有 1 个值
|
||||
List<Integer> ids = Arrays.asList(1);
|
||||
QueryWrapper qw = new QueryWrapper();
|
||||
qw.where(ACCOUNT.ID.in(ids))
|
||||
|
||||
System.out.println(qw.toSQL());
|
||||
```
|
||||
输出的 SQL 如下:
|
||||
|
||||
```sql
|
||||
select * from tb_account where id = 1;
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 存在疑问?
|
||||
|
||||
**疑问1:示例代码中的 QueryWrapper 所需要的 "ACCOUNT" 从哪里来的?**
|
||||
|
||||
@ -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,10 +115,132 @@ public void doSomething(){
|
||||
}
|
||||
```
|
||||
|
||||
在以上的例子中,两次 `Db.update(...)` 虽然是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候,
|
||||
在以上的例子中,执行了两次 `Db.updateBySql(...)`,它们是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候,
|
||||
它们都会进行回滚(rollback)。
|
||||
|
||||
以上提到的 `并非原子操作`,指的是:
|
||||
|
||||
>假设在回滚的时候,恰好其中一个数据库出现了异常(比如 网络问题,数据库崩溃),此时,可能只有一个数据库的数据正常回滚(rollback)。
|
||||
> 但无论如何,MyBatis-Flex 都会保证在同一个 `@Transactional` 中的多个数据源,保持相同的 commit 或者 rollback 行为。
|
||||
|
||||
## Seata 分布式事务
|
||||
|
||||
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
|
||||
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
|
||||
官方网站:https://seata.io/zh-cn/index.html
|
||||
|
||||
|
||||
### 开始使用
|
||||
|
||||
**第 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 使用两阶段提交(2PC,Two-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
|
||||
|
||||
### 注意事项
|
||||
1.使用`seata-spring-boot-starter`的时候请关闭自动代理
|
||||
```yaml
|
||||
seata:
|
||||
enable-auto-data-source-proxy: false
|
||||
```
|
||||
2.使用 `seata-all` 请不要使用 `@EnableAutoDataSourceProxy`
|
||||
|
||||
3.如果是 SpringBoot 项目需要引入相关 Maven 依赖,例如:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.seata</groupId>
|
||||
<artifactId>seata-spring-boot-starter</artifactId>
|
||||
<version>1.7.0</version>
|
||||
</dependency>
|
||||
```
|
||||
### 示例
|
||||
|
||||
[mybatis-flex-spring-boot-seata-demo](https://gitee.com/mybatis-flex/mybatis-flex-samples/tree/master/mybatis-flex-spring-boot-seata-demo) : Seata 官方 demo 与 flex 结合。
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
就可以了,不需要再添加其他 MyBatis 依赖。
|
||||
- 3、是否与 `mybatis-plus-boot-starter` 共用,使 MyBatis 被优先初始化,而导致 MyBatis-Flex 没有被加载。
|
||||
- 4、是否添加了 `pagehelper-spring-boot-starter` 依赖,导致传递了 `mybatis-spring-boot-starter` 依赖。如还想继续使用 pagehelper 插件,点击 [这里](#与-pagehelper-集成出现错误) 查看解决方案。
|
||||
- 5、是否 Spring Boot 版本过低,请使用 Spring Boot 2.2 及其以上版本,点击 [这里](#springboot-项目启动报错-javalangclassnotfoundexception-orgspringframeworktransactiontransactionmanager) 获取详细信息。
|
||||
|
||||
## 示例中的 AccountMapper 和 "ACCOUNT" 在哪里,报错了。
|
||||
|
||||
@ -62,6 +63,11 @@ in alimaven (http://maven.aliyun.com/nexus/content/groups/public/)
|
||||
</mirror>
|
||||
```
|
||||
|
||||
## SpringBoot 项目,启动报错 java.lang.ClassNotFoundException: org.springframework.transaction.TransactionManager
|
||||
|
||||
这个应该是 Spring Boot 版本的问题,`org.springframework.transaction.TransactionManager` 这个类是 Spring Framework 5.2
|
||||
新增的,对应 Spring Boot 的版本应该是 Spring Boot 2.2 及其以上版本,所以应该使用 Spring Boot 2.2 及其以上版本。
|
||||
|
||||
## SpringBoot 项目,启动报错 Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
|
||||
|
||||
如果当前依赖没有连接池相关依赖,则建议添加 HikariCP 依赖。
|
||||
|
||||
82
docs/zh/intro/gradle.md
Normal file
82
docs/zh/intro/gradle.md
Normal file
@ -0,0 +1,82 @@
|
||||
# Gradle 依赖
|
||||
|
||||
> 以下的 xml gradle 依赖示例中,可能并非最新的 MyBatis-Flex 版本,请自行查看最新版本,并修改版本号。
|
||||
>
|
||||
> 建议配置 annotationProcessor,那么可以省略mybatis-flex-processor的依赖
|
||||
>
|
||||
|
||||
|
||||
1、只用到了 MyBatis,没用到 Spring 的场景:
|
||||
|
||||
**【Kotlin】**
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("com.mybatis-flex:mybatis-flex-core:1.5.6")
|
||||
compileOnly("com.mybatis-flex:mybatis-flex-processor:1.5.6")
|
||||
}
|
||||
```
|
||||
|
||||
**【Groovy】**
|
||||
```groovy
|
||||
dependencies {
|
||||
implementation 'com.mybatis-flex:mybatis-flex-core:1.5.6'
|
||||
compileOnly 'com.mybatis-flex:mybatis-flex-processor:1.5.6'
|
||||
}
|
||||
```
|
||||
|
||||
2、用到了 Spring 的场景
|
||||
|
||||
**【Kotlin】**
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("com.mybatis-flex:mybatis-flex-spring:1.5.6")
|
||||
compileOnly("com.mybatis-flex:mybatis-flex-processor:1.5.6")
|
||||
}
|
||||
```
|
||||
|
||||
**【Groovy】**
|
||||
```groovy
|
||||
dependencies {
|
||||
implementation 'com.mybatis-flex:mybatis-flex-spring:1.5.6'
|
||||
compileOnly 'com.mybatis-flex:mybatis-flex-processor:1.5.6'
|
||||
}
|
||||
```
|
||||
3、用到了 Spring Boot 的场景
|
||||
|
||||
**【Kotlin】**
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("com.mybatis-flex:mybatis-flex-spring-boot-starter:1.5.6")
|
||||
compileOnly("com.mybatis-flex:mybatis-flex-processor:1.5.6")
|
||||
}
|
||||
```
|
||||
|
||||
**【Groovy】**
|
||||
```groovy
|
||||
dependencies {
|
||||
implementation 'com.mybatis-flex:mybatis-flex-spring-boot-starter:1.5.6'
|
||||
compileOnly 'com.mybatis-flex:mybatis-flex-processor:1.5.6'
|
||||
}
|
||||
```
|
||||
|
||||
4. 配置 annotationProcessor
|
||||
|
||||
`mybatis-flex-processor`提供APT服务,可以配置到annotationProcessorPaths,配置后,无需在依赖中声明`mybatis-flex-processor`依赖。
|
||||
|
||||
参考:[APT 设置-和 Lombok、Mapstruct 整合](../others/apt.md)
|
||||
|
||||
> 在Kotlin中使用时,请参考[在Kotlin中使用注解处理器](../kotlin/kapt.md)
|
||||
|
||||
**【Kotlin】**
|
||||
```kotlin
|
||||
dependencies {
|
||||
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor:1.5.6")
|
||||
}
|
||||
```
|
||||
|
||||
**【Groovy】**
|
||||
```groovy
|
||||
dependencies {
|
||||
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor:1.5.6'
|
||||
}
|
||||
```
|
||||
@ -60,6 +60,8 @@
|
||||
|
||||
参考:[APT 设置-和 Lombok、Mapstruct 整合](../others/apt.md)
|
||||
|
||||
> 在Kotlin中使用时,请参考[在Kotlin中使用注解处理器](../kotlin/kapt.md)
|
||||
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@ -76,4 +78,3 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
```
|
||||
|
||||
|
||||
63
docs/zh/kotlin/kapt.md
Normal file
63
docs/zh/kotlin/kapt.md
Normal file
@ -0,0 +1,63 @@
|
||||
# 在Kotlin中使用注解处理器
|
||||
|
||||
> 在Kotlin中想要使`@Table`等注解生效十分简单。只需要使用kapt即可。
|
||||
>
|
||||
|
||||
## 在Gradle中使用
|
||||
|
||||
1. 应用Gradle插件:kotlin-kapt
|
||||
|
||||
**【Kotlin】**
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
kotlin("kapt") version "1.9.0"
|
||||
}
|
||||
```
|
||||
|
||||
**【Groovy】**
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.kapt" version "1.9.0"
|
||||
}
|
||||
```
|
||||
|
||||
2. 在 dependencies 块中使用 kapt 配置添加相应的依赖项
|
||||
**【Kotlin】**
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
kapt("org.springframework.boot:spring-boot-configuration-processor:1.5.6")
|
||||
}
|
||||
```
|
||||
|
||||
**【Groovy】**
|
||||
```groovy
|
||||
dependencies {
|
||||
kapt 'org.springframework.boot:spring-boot-configuration-processor:1.5.6'
|
||||
}
|
||||
```
|
||||
|
||||
## 在Maven中使用
|
||||
在 compile 之前在 kotlin-maven-plugin 中添加 kapt 目标的执行:
|
||||
|
||||
```xml
|
||||
<execution>
|
||||
<id>kapt</id>
|
||||
<goals>
|
||||
<goal>kapt</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
```
|
||||
|
||||
> 关于Kapt更详细的说明,请看[Kotlin官网说明](https://book.kotlincn.net/text/kapt.html),或[Kotlin语言中文站](https://www.kotlincn.net/docs/reference/kapt.html)。
|
||||
@ -25,6 +25,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 默认方言抽象类。
|
||||
*
|
||||
* @author michael
|
||||
*/
|
||||
public abstract class JdbcDialect implements IDialect {
|
||||
@ -47,7 +48,7 @@ public abstract class JdbcDialect implements IDialect {
|
||||
column.setRawLength(columnMetaData.getColumnDisplaySize(i));
|
||||
|
||||
String jdbcType = columnMetaData.getColumnClassName(i);
|
||||
column.setPropertyType(JdbcTypeMapping.getType(jdbcType));
|
||||
column.setPropertyType(JdbcTypeMapping.getType(jdbcType, column.getRawLength()));
|
||||
|
||||
column.setAutoIncrement(columnMetaData.isAutoIncrement(i));
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ public class JdbcTypeMapping {
|
||||
}
|
||||
|
||||
private static final Map<String, String> mapping = new HashMap<>();
|
||||
private static JdbcTypeMapper mapper;
|
||||
|
||||
static {
|
||||
registerMapping("[B", "byte[]");
|
||||
@ -46,6 +47,14 @@ public class JdbcTypeMapping {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public static JdbcTypeMapper getMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
public static void setMapper(JdbcTypeMapper mapper) {
|
||||
JdbcTypeMapping.mapper = mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当只使用 date 类型来映射数据库的所有 "时间" 类型时,调用此方法
|
||||
*/
|
||||
@ -56,9 +65,17 @@ public class JdbcTypeMapping {
|
||||
registerMapping("java.time.LocalDate", "java.util.Date");
|
||||
}
|
||||
|
||||
static String getType(String jdbcType) {
|
||||
static String getType(String jdbcType, int length) {
|
||||
if (mapper != null) {
|
||||
return mapper.getType(jdbcType, length);
|
||||
}
|
||||
|
||||
String registered = mapping.get(jdbcType);
|
||||
return StringUtil.isNotBlank(registered) ? registered : jdbcType;
|
||||
}
|
||||
|
||||
public interface JdbcTypeMapper {
|
||||
String getType(String jdbcType, int length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import com.mybatisflex.codegen.config.TableConfig;
|
||||
import com.mybatisflex.codegen.config.TableDefConfig;
|
||||
import com.mybatisflex.codegen.constant.TemplateConst;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@ -150,7 +149,7 @@ public class GeneratorTest {
|
||||
generator.generate();
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Test
|
||||
public void testCodeGen3() {
|
||||
//配置数据源
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
@ -226,7 +225,7 @@ public class GeneratorTest {
|
||||
return globalConfig;
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Test
|
||||
public void testCodeGen4() {
|
||||
// 配置数据源
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition eq(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.EQUALS, value);
|
||||
@ -148,7 +148,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
|
||||
|
||||
public <T> QueryCondition eq(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.EQUALS, value).when(fn);
|
||||
@ -161,14 +161,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition ne(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition ne(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value).when(fn);
|
||||
@ -181,14 +181,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition like(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%");
|
||||
}
|
||||
|
||||
public <T> QueryCondition like(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%").when(fn);
|
||||
@ -196,14 +196,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
|
||||
|
||||
public QueryCondition likeLeft(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, value + "%");
|
||||
}
|
||||
|
||||
public <T> QueryCondition likeLeft(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, value + "%").when(fn);
|
||||
@ -211,14 +211,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
|
||||
|
||||
public QueryCondition likeRight(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition likeRight(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value).when(fn);
|
||||
@ -226,35 +226,34 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
|
||||
|
||||
public QueryCondition likeRaw(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition likeRaw(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LIKE, value).when(fn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* not like %%
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition notLike(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value + "%");
|
||||
}
|
||||
|
||||
public <T> QueryCondition notLike(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value + "%").when(fn);
|
||||
@ -262,14 +261,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
|
||||
|
||||
public QueryCondition notLikeLeft(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_LIKE, value + "%");
|
||||
}
|
||||
|
||||
public <T> QueryCondition notLikeLeft(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_LIKE, value + "%").when(fn);
|
||||
@ -277,35 +276,34 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
|
||||
|
||||
public QueryCondition notLikeRight(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition notLikeRight(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value).when(fn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 大于 greater than
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition gt(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.GT, value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition gt(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.GT, value).when(fn);
|
||||
@ -317,14 +315,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition ge(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.GE, value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition ge(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.GE, value).when(fn);
|
||||
@ -336,14 +334,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition lt(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LT, value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition lt(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LT, value).when(fn);
|
||||
@ -355,14 +353,14 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param value
|
||||
*/
|
||||
public QueryCondition le(Object value) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LE, value);
|
||||
}
|
||||
|
||||
public <T> QueryCondition le(Object value, Predicate<T> fn) {
|
||||
if (value == null) {
|
||||
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.LE, value).when(fn);
|
||||
@ -372,7 +370,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
/**
|
||||
* IS NULL
|
||||
*
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition isNull() {
|
||||
return QueryCondition.create(this, SqlConsts.IS_NULL, null);
|
||||
@ -386,7 +384,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
/**
|
||||
* IS NOT NULL
|
||||
*
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition isNotNull() {
|
||||
return QueryCondition.create(this, SqlConsts.IS_NOT_NULL, null);
|
||||
@ -401,21 +399,32 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* in arrays
|
||||
*
|
||||
* @param arrays
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition in(Object... arrays) {
|
||||
//忽略 QueryWrapper.in("name", null) 的情况
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null) || QueryColumnBehavior.shouldIgnoreValue(arrays)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
|
||||
if (arrays.length == 1 && QueryColumnBehavior.isSmartConvertInToEquals()) {
|
||||
return QueryCondition.create(this, SqlConsts.EQUALS, arrays[0]);
|
||||
}
|
||||
|
||||
return QueryCondition.create(this, SqlConsts.IN, arrays);
|
||||
}
|
||||
|
||||
|
||||
public <T> QueryCondition in(Object[] arrays, Predicate<T> fn) {
|
||||
//忽略 QueryWrapper.in("name", null) 的情况
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null) || QueryColumnBehavior.shouldIgnoreValue(arrays)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
|
||||
if (arrays.length == 1 && QueryColumnBehavior.isSmartConvertInToEquals()) {
|
||||
return QueryCondition.create(this, SqlConsts.EQUALS, arrays[0]);
|
||||
}
|
||||
|
||||
return QueryCondition.create(this, SqlConsts.IN, arrays).when(fn);
|
||||
}
|
||||
|
||||
@ -423,13 +432,20 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* in child select
|
||||
*
|
||||
* @param queryWrapper
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition in(QueryWrapper queryWrapper) {
|
||||
if (queryWrapper == null || QueryColumnBehavior.shouldIgnoreValue(queryWrapper)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.IN, queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
public <T> QueryCondition in(QueryWrapper queryWrapper, Predicate<T> fn) {
|
||||
if (queryWrapper == null || QueryColumnBehavior.shouldIgnoreValue(queryWrapper)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.IN, queryWrapper).when(fn);
|
||||
}
|
||||
|
||||
@ -438,17 +454,17 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* in Collection
|
||||
*
|
||||
* @param collection
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition in(Collection<?> collection) {
|
||||
if (collection != null && !collection.isEmpty()) {
|
||||
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
|
||||
return in(collection.toArray());
|
||||
}
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
|
||||
public <T> QueryCondition in(Collection<?> collection, Predicate<T> fn) {
|
||||
if (collection != null && !collection.isEmpty()) {
|
||||
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
|
||||
return in(collection.toArray(), fn);
|
||||
}
|
||||
return QueryCondition.createEmpty();
|
||||
@ -458,21 +474,31 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* not int arrays
|
||||
*
|
||||
* @param arrays
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition notIn(Object... arrays) {
|
||||
//忽略 QueryWrapper.notIn("name", null) 的情况
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null) || QueryColumnBehavior.shouldIgnoreValue(arrays)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
|
||||
if (arrays.length == 1 && QueryColumnBehavior.isSmartConvertInToEquals()) {
|
||||
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, arrays[0]);
|
||||
}
|
||||
|
||||
return QueryCondition.create(this, SqlConsts.NOT_IN, arrays);
|
||||
}
|
||||
|
||||
public <T> QueryCondition notIn(Object[] arrays, Predicate<T> fn) {
|
||||
//忽略 QueryWrapper.notIn("name", null) 的情况
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
|
||||
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null) || QueryColumnBehavior.shouldIgnoreValue(arrays)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
|
||||
if (arrays.length == 1 && QueryColumnBehavior.isSmartConvertInToEquals()) {
|
||||
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, arrays[0]);
|
||||
}
|
||||
|
||||
return QueryCondition.create(this, SqlConsts.NOT_IN, arrays).when(fn);
|
||||
}
|
||||
|
||||
@ -481,17 +507,17 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* not in Collection
|
||||
*
|
||||
* @param collection
|
||||
* @return
|
||||
* @return QueryCondition
|
||||
*/
|
||||
public QueryCondition notIn(Collection<?> collection) {
|
||||
if (collection != null && !collection.isEmpty()) {
|
||||
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
|
||||
return notIn(collection.toArray());
|
||||
}
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
|
||||
public <T> QueryCondition notIn(Collection<?> collection, Predicate<T> fn) {
|
||||
if (collection != null && !collection.isEmpty()) {
|
||||
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
|
||||
return notIn(collection.toArray(), fn);
|
||||
}
|
||||
return QueryCondition.createEmpty();
|
||||
@ -503,10 +529,17 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
* @param queryWrapper
|
||||
*/
|
||||
public QueryCondition notIn(QueryWrapper queryWrapper) {
|
||||
if (queryWrapper == null || QueryColumnBehavior.shouldIgnoreValue(queryWrapper)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_IN, queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
public <T> QueryCondition notIn(QueryWrapper queryWrapper, Predicate<T> fn) {
|
||||
if (queryWrapper == null || QueryColumnBehavior.shouldIgnoreValue(queryWrapper)) {
|
||||
return QueryCondition.createEmpty();
|
||||
}
|
||||
return QueryCondition.create(this, SqlConsts.NOT_IN, queryWrapper).when(fn);
|
||||
}
|
||||
|
||||
@ -615,7 +648,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (selfTable != null && StringUtil.isNotBlank(selfTable.alias)){
|
||||
if (selfTable != null && StringUtil.isNotBlank(selfTable.alias)) {
|
||||
return selfTable;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author michael
|
||||
*/
|
||||
public class QueryColumnBehavior {
|
||||
|
||||
/**
|
||||
* 自定义全局的自动忽略参数的方法
|
||||
*/
|
||||
private static Predicate<Object> ignoreFunction;
|
||||
|
||||
/**
|
||||
* 是否自动把 in(...) 只有 1 个参数的内容转换为相等 =
|
||||
*/
|
||||
private static boolean smartConvertInToEquals = false;
|
||||
|
||||
|
||||
public static Predicate<Object> getIgnoreFunction() {
|
||||
return ignoreFunction;
|
||||
}
|
||||
|
||||
public static void setIgnoreFunction(Predicate<Object> ignoreFunction) {
|
||||
QueryColumnBehavior.ignoreFunction = ignoreFunction;
|
||||
}
|
||||
|
||||
public static boolean isSmartConvertInToEquals() {
|
||||
return smartConvertInToEquals;
|
||||
}
|
||||
|
||||
public static void setSmartConvertInToEquals(boolean smartConvertInToEquals) {
|
||||
QueryColumnBehavior.smartConvertInToEquals = smartConvertInToEquals;
|
||||
}
|
||||
|
||||
|
||||
static boolean shouldIgnoreValue(Object value){
|
||||
if (ignoreFunction == null){
|
||||
return false;
|
||||
}
|
||||
return ignoreFunction.test(value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,9 +25,7 @@ import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.datasource.DataSourceKey;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.row.Row;
|
||||
import com.mybatisflex.core.util.ClassUtil;
|
||||
import com.mybatisflex.core.util.CollectionUtil;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import com.mybatisflex.core.util.*;
|
||||
import org.apache.ibatis.util.MapUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -121,6 +119,19 @@ public class RelationManager {
|
||||
RelationManager.ignoreRelations.set(ignoreRelations);
|
||||
}
|
||||
|
||||
|
||||
public static <T> void addIgnoreRelations(LambdaGetter<T>... ignoreRelations) {
|
||||
Set<String> relations = RelationManager.ignoreRelations.get();
|
||||
if (relations == null) {
|
||||
relations = new HashSet<>();
|
||||
setIgnoreRelations(relations);
|
||||
}
|
||||
for (LambdaGetter<T> lambdaGetter : ignoreRelations) {
|
||||
String fieldName = LambdaUtil.getFieldName(lambdaGetter);
|
||||
relations.add(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addIgnoreRelations(String... ignoreRelations) {
|
||||
Set<String> relations = RelationManager.ignoreRelations.get();
|
||||
if (relations == null) {
|
||||
|
||||
@ -17,6 +17,8 @@ package com.mybatisflex.core.table;
|
||||
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
|
||||
public class IdInfo extends ColumnInfo {
|
||||
|
||||
@ -53,16 +55,38 @@ public class IdInfo extends ColumnInfo {
|
||||
if (Number.class.isAssignableFrom(columnInfo.getPropertyType())) {
|
||||
keyType = KeyType.Auto;
|
||||
} else {
|
||||
keyType = KeyType.None;
|
||||
initDefaultKeyType();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public IdInfo(Id id) {
|
||||
this.keyType = id.keyType();
|
||||
this.value = id.value();
|
||||
this.before = id.before();
|
||||
|
||||
initDefaultKeyType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户未配置 keyType 是,配置默认的 key Type
|
||||
*/
|
||||
private void initDefaultKeyType() {
|
||||
if (this.keyType == null || this.keyType == KeyType.None) {
|
||||
FlexGlobalConfig.KeyConfig defaultKeyConfig = FlexGlobalConfig.getDefaultConfig().getKeyConfig();
|
||||
if (defaultKeyConfig != null) {
|
||||
if (defaultKeyConfig.getKeyType() != null) {
|
||||
this.keyType = defaultKeyConfig.getKeyType();
|
||||
this.before = defaultKeyConfig.isBefore();
|
||||
}
|
||||
if (StringUtil.isBlank(this.value) && StringUtil.isNotBlank(defaultKeyConfig.getValue())) {
|
||||
this.value = defaultKeyConfig.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public KeyType getKeyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
@ -370,11 +370,14 @@ public class TableInfo {
|
||||
this.primaryColumns = new String[primaryKeyList.size()];
|
||||
|
||||
List<String> insertIdFields = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < primaryKeyList.size(); i++) {
|
||||
IdInfo idInfo = primaryKeyList.get(i);
|
||||
primaryColumns[i] = idInfo.getColumn();
|
||||
|
||||
if (idInfo.getKeyType() != KeyType.Auto && (idInfo.getBefore() != null && idInfo.getBefore())) {
|
||||
if (idInfo.getKeyType() != KeyType.Auto
|
||||
|| (idInfo.getBefore() != null && idInfo.getBefore())
|
||||
) {
|
||||
insertIdFields.add(idInfo.getColumn());
|
||||
}
|
||||
|
||||
|
||||
@ -82,35 +82,62 @@ public class UpdateChain<T> extends QueryWrapperAdapter<UpdateChain<T>> {
|
||||
return new UpdateChain<>(baseMapper);
|
||||
}
|
||||
|
||||
public UpdateChain<T> set(String property, Object value, boolean condition) {
|
||||
entityWrapper.set(property, value, condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> set(String property, Object value) {
|
||||
entityWrapper.set(property, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> set(LambdaGetter<T> getter, Object value, boolean condition) {
|
||||
entityWrapper.set(getter, value, condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> set(LambdaGetter<T> getter, Object value) {
|
||||
entityWrapper.set(getter, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> set(QueryColumn queryColumn, Object value, boolean condition) {
|
||||
entityWrapper.set(queryColumn, value, condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public UpdateChain<T> set(QueryColumn queryColumn, Object value) {
|
||||
entityWrapper.set(queryColumn, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(String property, Object value, boolean condition) {
|
||||
entityWrapper.setRaw(property, value, condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(String property, Object value) {
|
||||
entityWrapper.setRaw(property, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(LambdaGetter<T> getter, Object value, boolean condition) {
|
||||
entityWrapper.setRaw(getter, value, condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(LambdaGetter<T> getter, Object value) {
|
||||
entityWrapper.setRaw(getter, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value, boolean condition) {
|
||||
entityWrapper.setRaw(queryColumn, value, condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value) {
|
||||
entityWrapper.set(queryColumn, value);
|
||||
return this;
|
||||
|
||||
@ -36,6 +36,12 @@ public interface UpdateWrapper extends Serializable {
|
||||
return handler.getUpdates();
|
||||
}
|
||||
|
||||
default UpdateWrapper set(String property, Object value, boolean condition) {
|
||||
if (condition) {
|
||||
return set(property, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default UpdateWrapper set(String property, Object value) {
|
||||
if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
|
||||
@ -46,6 +52,12 @@ public interface UpdateWrapper extends Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
default <T> UpdateWrapper set(LambdaGetter<T> getter, Object value, boolean condition) {
|
||||
if (condition) {
|
||||
return set(getter, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default <T> UpdateWrapper set(LambdaGetter<T> getter, Object value) {
|
||||
if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
|
||||
@ -57,6 +69,12 @@ public interface UpdateWrapper extends Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
default <T> UpdateWrapper set(QueryColumn queryColumn, Object value, boolean condition) {
|
||||
if (condition) {
|
||||
return set(queryColumn, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default <T> UpdateWrapper set(QueryColumn queryColumn, Object value) {
|
||||
if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
|
||||
@ -67,17 +85,41 @@ public interface UpdateWrapper extends Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
default UpdateWrapper setRaw(String property, Object value, boolean condition) {
|
||||
if (condition) {
|
||||
return setRaw(property, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
default UpdateWrapper setRaw(String property, Object value) {
|
||||
getUpdates().put(property, new RawValue(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
default <T> UpdateWrapper setRaw(LambdaGetter<T> getter, Object value, boolean condition) {
|
||||
if (condition) {
|
||||
return setRaw(getter, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
default <T> UpdateWrapper setRaw(LambdaGetter<T> getter, Object value) {
|
||||
getUpdates().put(LambdaUtil.getFieldName(getter), new RawValue(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
default <T> UpdateWrapper setRaw(QueryColumn queryColumn, Object value, boolean condition) {
|
||||
if (condition) {
|
||||
return setRaw(queryColumn, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default <T> UpdateWrapper setRaw(QueryColumn queryColumn, Object value) {
|
||||
getUpdates().put(queryColumn.getName(), new RawValue(value));
|
||||
return this;
|
||||
|
||||
@ -17,6 +17,7 @@ package com.mybatisflex.core.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.regex.Matcher;
|
||||
@ -146,7 +147,7 @@ public class SqlUtil {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
// number
|
||||
// number or bool
|
||||
else if (value instanceof Number || value instanceof Boolean) {
|
||||
return value.toString();
|
||||
}
|
||||
@ -165,7 +166,7 @@ public class SqlUtil {
|
||||
if (value instanceof Date) {
|
||||
sb.append(DateUtil.toDateTimeString((Date) value));
|
||||
} else if (value instanceof LocalDateTime) {
|
||||
sb.append(DateUtil.toDateTimeString(DateUtil.toDate((LocalDateTime) value)));
|
||||
sb.append(((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
} else {
|
||||
sb.append(value);
|
||||
}
|
||||
|
||||
@ -91,6 +91,12 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.seata</groupId>
|
||||
<artifactId>seata-rm-datasource</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@ -19,7 +19,11 @@ import com.mybatisflex.core.datasource.DataSourceBuilder;
|
||||
import com.mybatisflex.core.datasource.DataSourceDecipher;
|
||||
import com.mybatisflex.core.datasource.DataSourceManager;
|
||||
import com.mybatisflex.core.datasource.FlexDataSource;
|
||||
import com.mybatisflex.spring.SeataMode;
|
||||
import com.mybatisflex.spring.boot.MybatisFlexProperties.SeataConfig;
|
||||
import com.mybatisflex.spring.datasource.DataSourceAdvice;
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
import io.seata.rm.datasource.xa.DataSourceProxyXA;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
@ -53,6 +57,8 @@ public class MultiDataSourceAutoConfiguration {
|
||||
|
||||
private final Map<String, Map<String, String>> dataSourceProperties;
|
||||
|
||||
private final SeataConfig seataConfig;
|
||||
|
||||
//数据源解密器
|
||||
protected final DataSourceDecipher dataSourceDecipher;
|
||||
|
||||
@ -62,6 +68,7 @@ public class MultiDataSourceAutoConfiguration {
|
||||
) {
|
||||
dataSourceProperties = properties.getDatasource();
|
||||
dataSourceDecipher = dataSourceDecipherProvider.getIfAvailable();
|
||||
seataConfig = properties.getSeataConfig();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ -75,11 +82,22 @@ public class MultiDataSourceAutoConfiguration {
|
||||
DataSourceManager.setDecipher(dataSourceDecipher);
|
||||
|
||||
for (Map.Entry<String, Map<String, String>> entry : dataSourceProperties.entrySet()) {
|
||||
|
||||
DataSource dataSource = new DataSourceBuilder(entry.getValue()).build();
|
||||
DataSourceManager.decryptDataSource(dataSource);
|
||||
|
||||
if (seataConfig != null && seataConfig.isEnable()) {
|
||||
if (seataConfig.getSeataMode() == SeataMode.XA) {
|
||||
dataSource = new DataSourceProxyXA(dataSource);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ package com.mybatisflex.spring.boot;
|
||||
|
||||
import com.mybatisflex.core.FlexConsts;
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.spring.SeataMode;
|
||||
import org.apache.ibatis.io.VFS;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.mapping.ResultSetType;
|
||||
@ -122,6 +123,19 @@ public class MybatisFlexProperties {
|
||||
*/
|
||||
private CoreConfiguration configuration;
|
||||
|
||||
/**
|
||||
* A Configuration object for seata
|
||||
*/
|
||||
private SeataConfig seataConfig;
|
||||
|
||||
public SeataConfig getSeataConfig() {
|
||||
return seataConfig;
|
||||
}
|
||||
|
||||
public void setSeataConfig(SeataConfig seataConfig) {
|
||||
this.seataConfig = seataConfig;
|
||||
}
|
||||
|
||||
public Map<String, Map<String, String>> getDatasource() {
|
||||
return datasource;
|
||||
}
|
||||
@ -890,4 +904,38 @@ public class MybatisFlexProperties {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Seata 配置
|
||||
*
|
||||
* @author life
|
||||
*/
|
||||
public static class SeataConfig{
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
private boolean enable = false;
|
||||
|
||||
/**
|
||||
* 事务模式支持,只支持XA或者AT
|
||||
*/
|
||||
private SeataMode seataMode = SeataMode.AT;
|
||||
|
||||
public boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public void setEnable(boolean enable) {
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
public SeataMode getSeataMode() {
|
||||
return seataMode;
|
||||
}
|
||||
|
||||
public void setSeataMode(SeataMode seataMode) {
|
||||
this.seataMode = seataMode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -40,6 +40,12 @@
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.seata</groupId>
|
||||
<artifactId>seata-spring-boot-starter</artifactId>
|
||||
<version>1.7.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@ -88,6 +88,6 @@ public class FlexSpringTransaction implements Transaction {
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() throws SQLException {
|
||||
return getConnection().getNetworkTimeout();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ import com.mybatisflex.core.FlexConsts;
|
||||
import com.mybatisflex.core.datasource.FlexDataSource;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
import io.seata.rm.datasource.xa.DataSourceProxyXA;
|
||||
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
|
||||
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
|
||||
import org.apache.ibatis.cache.Cache;
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.spring;
|
||||
|
||||
/**
|
||||
* @author life
|
||||
*/
|
||||
public enum SeataMode {
|
||||
|
||||
XA,
|
||||
|
||||
AT
|
||||
}
|
||||
149
mybatis-flex-test/mybatis-flex-spring-boot-seata/pom.xml
Normal file
149
mybatis-flex-test/mybatis-flex-spring-boot-seata/pom.xml
Normal file
@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>mybatis-flex-test</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.6</version>
|
||||
</parent>
|
||||
<groupId>com.mybatisfle.test</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot-seata</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>mybatis-flex-spring-boot-seata</name>
|
||||
<description>mybatis-flex-spring-boot-seata</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-flex.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-codegen</artifactId>
|
||||
<version>${mybatis-flex.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.32</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.2.18</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-jdbc</artifactId>-->
|
||||
<!-- <version>2.7.9</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework</groupId>-->
|
||||
<!-- <artifactId>spring-jdbc</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.h2database</groupId>-->
|
||||
<!-- <artifactId>h2</artifactId>-->
|
||||
<!-- <version>2.1.214</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.yaml</groupId>-->
|
||||
<!-- <artifactId>snakeyaml</artifactId>-->
|
||||
<!-- <version>1.33</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,15 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@MapperScan("com.mybatisfle.test.mybatisflexspringbootseata")
|
||||
@SpringBootApplication
|
||||
public class MybatisFlexSpringBootSeataApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MybatisFlexSpringBootSeataApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.controller;
|
||||
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.service.TestService;
|
||||
import com.mybatisflex.core.audit.AuditManager;
|
||||
import com.mybatisflex.core.audit.ConsoleMessageCollector;
|
||||
import com.mybatisflex.core.audit.MessageCollector;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class TestController {
|
||||
|
||||
|
||||
@Autowired
|
||||
TestService testService;
|
||||
|
||||
@RequestMapping("buy")
|
||||
public String buy(){
|
||||
//开启审计功能
|
||||
AuditManager.setAuditEnable(true);
|
||||
//设置 SQL 审计收集器
|
||||
MessageCollector collector = new ConsoleMessageCollector();
|
||||
AuditManager.setMessageCollector(collector);
|
||||
String flag =String.valueOf(testService.buy());
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.entity;
|
||||
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 实体类。
|
||||
*
|
||||
* @author life
|
||||
* @since 2023-08-03
|
||||
*/
|
||||
@Table(value = "account_tbl", schema = "db_account")
|
||||
public class AccountTbl implements Serializable {
|
||||
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Integer id;
|
||||
|
||||
private String userId;
|
||||
|
||||
private Integer money;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Integer getMoney() {
|
||||
return money;
|
||||
}
|
||||
|
||||
public void setMoney(Integer money) {
|
||||
this.money = money;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.entity;
|
||||
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 实体类。
|
||||
*
|
||||
* @author life
|
||||
* @since 2023-08-03
|
||||
*/
|
||||
@Table(value = "order_tbl", schema = "db_order")
|
||||
public class OrderTbl implements Serializable {
|
||||
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Integer id;
|
||||
|
||||
private String userId;
|
||||
|
||||
private String commodityCode;
|
||||
|
||||
private Integer count;
|
||||
|
||||
private Integer money;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getCommodityCode() {
|
||||
return commodityCode;
|
||||
}
|
||||
|
||||
public void setCommodityCode(String commodityCode) {
|
||||
this.commodityCode = commodityCode;
|
||||
}
|
||||
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Integer getMoney() {
|
||||
return money;
|
||||
}
|
||||
|
||||
public void setMoney(Integer money) {
|
||||
this.money = money;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.entity;
|
||||
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 实体类。
|
||||
*
|
||||
* @author life
|
||||
* @since 2023-08-03
|
||||
*/
|
||||
@Table(value = "stock_tbl", schema = "db_stock")
|
||||
public class StockTbl implements Serializable {
|
||||
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Integer id;
|
||||
|
||||
private String commodityCode;
|
||||
|
||||
private Integer count;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getCommodityCode() {
|
||||
return commodityCode;
|
||||
}
|
||||
|
||||
public void setCommodityCode(String commodityCode) {
|
||||
this.commodityCode = commodityCode;
|
||||
}
|
||||
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.mapper;
|
||||
|
||||
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.AccountTbl;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
/**
|
||||
* 映射层。
|
||||
*
|
||||
* @author life
|
||||
* @since 2023-08-03
|
||||
*/
|
||||
public interface AccountTblMapper extends BaseMapper<AccountTbl> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.mapper;
|
||||
|
||||
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.OrderTbl;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
/**
|
||||
* 映射层。
|
||||
*
|
||||
* @author life
|
||||
* @since 2023-08-03
|
||||
*/
|
||||
public interface OrderTblMapper extends BaseMapper<OrderTbl> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.mapper;
|
||||
|
||||
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.StockTbl;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
/**
|
||||
* 映射层。
|
||||
*
|
||||
* @author life
|
||||
* @since 2023-08-03
|
||||
*/
|
||||
public interface StockTblMapper extends BaseMapper<StockTbl> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.service;
|
||||
|
||||
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.AccountTbl;
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.OrderTbl;
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.StockTbl;
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.entity.table.AccountTblTableDef;
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.mapper.AccountTblMapper;
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.mapper.OrderTblMapper;
|
||||
import com.mybatisfle.test.mybatisflexspringbootseata.mapper.StockTblMapper;
|
||||
import com.mybatisflex.core.datasource.DataSourceKey;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import io.seata.core.context.RootContext;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import org.mybatis.logging.Logger;
|
||||
import org.mybatis.logging.LoggerFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class TestService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TestService.class);
|
||||
|
||||
@Autowired
|
||||
AccountTblMapper accountTblMapper;
|
||||
|
||||
@Autowired
|
||||
OrderTblMapper orderTblMapper;
|
||||
|
||||
@Autowired
|
||||
StockTblMapper stockTblMapper;
|
||||
|
||||
// @Transactional
|
||||
@GlobalTransactional
|
||||
public boolean buy() {
|
||||
// DataSourceKey.use("accountdb");
|
||||
LOGGER.warn(() -> "xid:"+RootContext.getXID());
|
||||
QueryWrapper account =new QueryWrapper();
|
||||
account.where(AccountTblTableDef.ACCOUNT_TBL.USER_ID.eq("1001"));
|
||||
AccountTbl accountTbl = accountTblMapper.selectOneByQuery(account);
|
||||
accountTbl.setMoney(accountTbl.getMoney() - 5);
|
||||
accountTblMapper.update(accountTbl);
|
||||
DataSourceKey.use("stockdb");
|
||||
QueryWrapper stock = new QueryWrapper();
|
||||
stock.where("id=1");
|
||||
StockTbl stockTbl = stockTblMapper.selectOneByQuery(stock);
|
||||
stockTbl.setCount(stockTbl.getCount() - 1);
|
||||
stockTblMapper.update(stockTbl);
|
||||
DataSourceKey.use("orderdb");
|
||||
OrderTbl orderTbl = new OrderTbl();
|
||||
orderTbl.setCount(5);
|
||||
orderTbl.setMoney(5);
|
||||
orderTbl.setUserId(accountTbl.getUserId());
|
||||
orderTbl.setCount(1);
|
||||
orderTbl.setCommodityCode(stockTbl.getCommodityCode());
|
||||
orderTblMapper.insert(orderTbl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata.utils;
|
||||
|
||||
import com.mybatisflex.codegen.Generator;
|
||||
import com.mybatisflex.codegen.config.ColumnConfig;
|
||||
import com.mybatisflex.codegen.config.GlobalConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
public class Codegen {
|
||||
|
||||
public static void main(String[] args) {
|
||||
//配置数据源
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db_stock?characterEncoding=utf-8");
|
||||
dataSource.setUsername("root");
|
||||
dataSource.setPassword("131496");
|
||||
|
||||
//创建配置内容,两种风格都可以。
|
||||
GlobalConfig globalConfig = createGlobalConfigUseStyle1();
|
||||
//GlobalConfig globalConfig = createGlobalConfigUseStyle2();
|
||||
|
||||
//通过 datasource 和 globalConfig 创建代码生成器
|
||||
Generator generator = new Generator(dataSource, globalConfig);
|
||||
|
||||
//生成代码
|
||||
generator.generate();
|
||||
}
|
||||
|
||||
public static GlobalConfig createGlobalConfigUseStyle1() {
|
||||
//创建配置内容
|
||||
GlobalConfig globalConfig = new GlobalConfig();
|
||||
|
||||
//设置根包
|
||||
globalConfig.setBasePackage("com.mybatisfle.test.mybatisflexspringbootseata");
|
||||
|
||||
//设置表前缀和只生成哪些表
|
||||
globalConfig.setGenerateSchema("db_stock");
|
||||
// globalConfig.setTablePrefix("tb_");
|
||||
globalConfig.setGenerateTable("stock_tbl");
|
||||
|
||||
//设置生成 entity 并启用 Lombok
|
||||
globalConfig.setEntityGenerateEnable(true);
|
||||
globalConfig.setEntityWithLombok(true);
|
||||
|
||||
//设置生成 mapper
|
||||
globalConfig.setMapperGenerateEnable(true);
|
||||
|
||||
//可以单独配置某个列
|
||||
// ColumnConfig columnConfig = new ColumnConfig();
|
||||
// columnConfig.setColumnName("tenant_id");
|
||||
// columnConfig.setLarge(true);
|
||||
// columnConfig.setVersion(true);
|
||||
// globalConfig.setColumnConfig("account", columnConfig);
|
||||
|
||||
return globalConfig;
|
||||
}
|
||||
|
||||
public static GlobalConfig createGlobalConfigUseStyle2() {
|
||||
//创建配置内容
|
||||
GlobalConfig globalConfig = new GlobalConfig();
|
||||
|
||||
//设置根包
|
||||
globalConfig.getPackageConfig()
|
||||
.setBasePackage("com.test");
|
||||
|
||||
//设置表前缀和只生成哪些表,setGenerateTable 未配置时,生成所有表
|
||||
globalConfig.getStrategyConfig()
|
||||
.setGenerateSchema("schema")
|
||||
.setTablePrefix("tb_")
|
||||
.setGenerateTable("account", "account_session");
|
||||
|
||||
//设置生成 entity 并启用 Lombok
|
||||
globalConfig.enableEntity()
|
||||
.setWithLombok(true);
|
||||
|
||||
//设置生成 mapper
|
||||
globalConfig.enableMapper();
|
||||
|
||||
//可以单独配置某个列
|
||||
ColumnConfig columnConfig = new ColumnConfig();
|
||||
columnConfig.setColumnName("tenant_id");
|
||||
columnConfig.setLarge(true);
|
||||
columnConfig.setVersion(true);
|
||||
globalConfig.getStrategyConfig()
|
||||
.setColumnConfig("account", columnConfig);
|
||||
|
||||
return globalConfig;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
|
||||
mybatis-flex:
|
||||
seata-config:
|
||||
enable: true #启动seata
|
||||
seata-mode: XA #xa或者ta
|
||||
datasource:
|
||||
accountdb:
|
||||
url: jdbc:mysql://127.0.0.1:3306/db_account
|
||||
username: root
|
||||
password: 131496
|
||||
orderdb:
|
||||
url: jdbc:mysql://127.0.0.1:3306/db_order
|
||||
username: root
|
||||
password: 131496
|
||||
stockdb:
|
||||
url: jdbc:mysql://127.0.0.1:3306/db_stock
|
||||
username: root
|
||||
password: 131496
|
||||
server:
|
||||
port: 2010
|
||||
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
|
||||
@ -0,0 +1,97 @@
|
||||
# Account
|
||||
DROP SCHEMA IF EXISTS db_account;
|
||||
CREATE SCHEMA db_account;
|
||||
USE db_account;
|
||||
|
||||
CREATE TABLE `account_tbl`
|
||||
(
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` VARCHAR(255) DEFAULT NULL,
|
||||
`money` INT(11) DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
INSERT INTO account_tbl (id, user_id, money)
|
||||
VALUES (1, '1001', 10000);
|
||||
INSERT INTO account_tbl (id, user_id, money)
|
||||
VALUES (2, '1002', 10000);
|
||||
|
||||
CREATE TABLE `undo_log`
|
||||
(
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`branch_id` bigint(20) NOT NULL,
|
||||
`xid` varchar(100) NOT NULL,
|
||||
`context` varchar(128) NOT NULL,
|
||||
`rollback_info` longblob NOT NULL,
|
||||
`log_status` int(11) NOT NULL,
|
||||
`log_created` datetime NOT NULL,
|
||||
`log_modified` datetime NOT NULL,
|
||||
`ext` varchar(100) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
|
||||
|
||||
# Order
|
||||
DROP SCHEMA IF EXISTS db_order;
|
||||
CREATE SCHEMA db_order;
|
||||
USE db_order;
|
||||
|
||||
CREATE TABLE `order_tbl`
|
||||
(
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` VARCHAR(255) DEFAULT NULL,
|
||||
`commodity_code` VARCHAR(255) DEFAULT NULL,
|
||||
`count` INT(11) DEFAULT '0',
|
||||
`money` INT(11) DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `undo_log`
|
||||
(
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`branch_id` bigint(20) NOT NULL,
|
||||
`xid` varchar(100) NOT NULL,
|
||||
`context` varchar(128) NOT NULL,
|
||||
`rollback_info` longblob NOT NULL,
|
||||
`log_status` int(11) NOT NULL,
|
||||
`log_created` datetime NOT NULL,
|
||||
`log_modified` datetime NOT NULL,
|
||||
`ext` varchar(100) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
|
||||
|
||||
# stock
|
||||
DROP SCHEMA IF EXISTS db_stock;
|
||||
CREATE SCHEMA db_stock;
|
||||
USE db_stock;
|
||||
|
||||
CREATE TABLE `stock_tbl`
|
||||
(
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`commodity_code` VARCHAR(255) DEFAULT NULL,
|
||||
`count` INT(11) DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `commodity_code` (`commodity_code`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
|
||||
INSERT INTO stock_tbl (id, commodity_code, count)
|
||||
VALUES (1, '2001', 1000);
|
||||
|
||||
CREATE TABLE `undo_log`
|
||||
(
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`branch_id` bigint(20) NOT NULL,
|
||||
`xid` varchar(100) NOT NULL,
|
||||
`context` varchar(128) NOT NULL,
|
||||
`rollback_info` longblob NOT NULL,
|
||||
`log_status` int(11) NOT NULL,
|
||||
`log_created` datetime NOT NULL,
|
||||
`log_modified` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
|
||||
@ -0,0 +1,13 @@
|
||||
package com.mybatisfle.test.mybatisflexspringbootseata;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class MybatisFlexSpringBootSeataApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,16 +7,16 @@ spring:
|
||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/flex_test
|
||||
username: root
|
||||
password: 123456
|
||||
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
|
||||
@ -38,11 +38,11 @@ mybatis-flex:
|
||||
# password: 12345678
|
||||
#mybatis-flex:
|
||||
# datasource:
|
||||
# ds1:
|
||||
# url: jdbc:mysql://127.0.0.1:3306/db
|
||||
# ds3333:
|
||||
# url: jdbc:mysql://127.0.0.1:3306/flex_test
|
||||
# username: root
|
||||
# password: 123456
|
||||
# password: 131496
|
||||
# ds2:
|
||||
# url: jdbc:mysql://127.0.0.1:3306/db2
|
||||
# url: jdbc:mysql://127.0.0.1:3306/flex_test1
|
||||
# username: root
|
||||
# password: 123456
|
||||
# password: 131496
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,6 +18,7 @@
|
||||
<module>mybatis-flex-spring-test</module>
|
||||
<module>mybatis-flex-spring-boot-test</module>
|
||||
<module>mybatis-flex-spring-cloud-test</module>
|
||||
<module>mybatis-flex-spring-boot-seata</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
@ -26,14 +27,6 @@
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<!-- <resources>-->
|
||||
<!-- <resource>-->
|
||||
<!-- <directory>src/main/resources</directory>-->
|
||||
<!-- <includes>-->
|
||||
<!-- <include>**/*</include>-->
|
||||
<!-- </includes>-->
|
||||
<!-- </resource>-->
|
||||
<!-- </resources>-->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user