Merge remote-tracking branch 'origin/main'

# Conflicts:
#	docs/zh/intro/gradle.md
#	docs/zh/others/kapt.md
This commit is contained in:
CloudPlayer 2023-08-12 19:15:32 +08:00
commit 9483ab9dfb
118 changed files with 2889 additions and 697 deletions

View File

@ -1,6 +1,34 @@
# MyBatis-Flex ChangeLog
## v1.5.7 20230812:
- 新增QueryWrapper 添加对 delete 和 update 的 left join 支持
- 新增RelationManager.addIgnoreRelations() 添加对 lambda 的支持
- 新增:添加 QueryColumnBehavior 用于自定义 QueryColumn 的某些行为特征
- 新增typeHandler 添加对泛型自动支持的功能
- 新增:多数据源新增对 Seata 分布式事务的支持,感谢 @lifejwang11
- 新增:添加对 Kotlin 的扩展支持,感谢 @kamo-sama
- 新增:添加 saveOrUpdateBatch 方法的支持,感谢 @Suomm
- 新增QueryModel 提供 as 方法的支持,感谢 @Suomm
- 新增:逻辑删除、乐观锁、多租户添加全局默认自动配置的功能,感谢 @Suomm
- 优化:移除 flex 自动把 id 属性设置为主键的功能
- 优化:重构链式调用的方法,统一链式调用和 ActiveRecord 的 API感谢 @Suomm
- 优化UpdateChian 支持设置 left join 的表数据的支持,感谢 @Suomm
- 修复db2 方言的 KeywordWrap 错误的问题
- 修复:在某些场景下 count 查询没有被替换的问题,感谢 @Suomm
- 修复QueryWrapper 的 or(consumer, condition) 方法逻辑错误,感谢 @Suomm
- 修复QueryColumn 由于 Predicate 没有类型约束可能导致类型转换异常的问题,感谢 @Suomm
- 修复OSGI 环境下Lambda 通过 ClassLoader 获取不到类的问题,感谢 @2han9wen71an
- 文档:更新视频教程的文档链接
- 文档:添加 SpringBoot 最低版本的说明文档,感谢 @Suomm
- 文档Seata 分布式事务的相关文档,感谢 @lifejwang11
- 文档增加了使用gradle构建时的文档说明感谢 @CloudPlayer
- 文档增加了在Kotlin中使用注解处理器的说明感谢 @CloudPlayer
- 文档:常见问题添加代码生成器获取不到注释说明,感谢 @Suomm
- 文档:常见问题添加 Spring Devtools 造成的类转换异常的相关文档
- 文档:常见问题添加 Nacos 集成启动出错的相关文档
## v1.5.6 20230804:
- 新增:代码生成器重构并新增对 Solon 框架的代码生成功能,感谢 @Suomm

View File

@ -46,6 +46,7 @@ export default defineConfig({
{text: 'MyBatis-Flex 是什么', link: '/zh/intro/what-is-mybatisflex'},
{text: '快速开始', link: '/zh/intro/getting-started'},
{text: 'Maven 依赖', link: '/zh/intro/maven'},
{text: 'Gradle 依赖', link: '/zh/intro/gradle'},
{text: '和同类框架「功能」对比', link: '/zh/intro/comparison'},
{text: '和同类框架「性能」对比', link: '/zh/intro/benchmark'},
{text: '使用 Mybatis 原生功能', link: '/zh/intro/use-mybatis-native'},
@ -100,6 +101,7 @@ export default defineConfig({
items: [
{text: '代码生成器', link: '/zh/others/codegen'},
{text: 'APT 设置', link: '/zh/others/apt'},
{text: 'KAPT 设置', link: '/zh/others/kapt'},
]
}
],

View File

@ -115,7 +115,7 @@ const {Layout} = DefaultTheme
<a href="https://gitee.com/sdyunze/iotlink" target="_blank"><img src="/assets/images/ad/iotlink_20240802.png"></a>
</div>
<div class="banner">
虚以待位
<a href="https://eiam.topiam.cn" target="_blank"><img src="/assets/images/ad/topiam_20230909.png" style="width: 105px;height: 50px"></a>
</div>
</div>
<div class="banner-bottom">

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -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因此会带来指数级的性能增长。
---

View File

@ -87,6 +87,10 @@
- [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)
- [MyBatis-Flex 视频教程 - 36 分页查询](https://www.bilibili.com/video/BV1d44y1F7JM)
- [MyBatis-Flex 视频教程 - 37 分页查询 count 查询优化](https://www.bilibili.com/video/BV1np4y1G7R9)
- [MyBatis-Flex 视频教程 - 38 基于 XML 文件的高性能分页](https://www.bilibili.com/video/BV1Zh4y1D7aj)
- [MyBatis-Flex 视频教程 - 39 Db + Row](https://www.bilibili.com/video/BV1wp4y1g7by)

View File

@ -8,13 +8,15 @@ SpringBoot 配置文件(`application.yml` 等)主要是用于对 MyBatis 原
mybatis-flex:
#......
datasource:
#......
#......
configuration:
#......
#......
global-config:
#......
#......
admin-config:
#......
#......
seata-config:
#......
```
## mybatis-flex
@ -129,7 +131,28 @@ TypeHandler 扫描路径如果配置了该属性SqlSessionFactoryBean 会
- 类型:`java.lang.Object`
- 默认值:`1`
逻辑删除数据删除标记值,
逻辑删除数据删除标记值。
### logic-delete-column
- 类型:`java.lang.String`
- 默认值:`del_flag`
默认的逻辑删除字段。
### tenant-column
- 类型:`java.lang.String`
- 默认值:`tenant_id`
默认的多租户字段。
### version-column
- 类型:`java.lang.String`
- 默认值:`version`
默认的乐观锁字段。
## admin-config
@ -152,4 +175,20 @@ MyBatis-Flex-Admin 连接端点。
- 类型:`String`
- 默认值:`null`
MyBatis-Flex-Admin 连接密钥。
MyBatis-Flex-Admin 连接密钥。
## seata-config
### enable
- 类型:`boolean`
- 默认值:`false`
是否启用 Seata 代理数据源。
### seata-mode
- 类型:`com.mybatisflex.spring.boot.MybatisFlexProperties.SeataMode`
- 默认值:`AT`
使用 Seata AT 模式代理数据源。

View File

@ -1017,7 +1017,7 @@ QueryWrapper query2 = QueryWrapper.create()
在以上的 `query1` 中,由于 `userName``id` 都为 nullMyBatis-Flex 会自动忽略 null 值的条件,因此,它们构建出来的 SQL 条件是和 `query2` 完全一致的 。
## QueryColumnBehavior <Badge type="tip" text="^ v1.5.6" />
## QueryColumnBehavior <Badge type="tip" text="^ v1.5.7" />
在以上的内容中,我们知道 MyBatis-Flex 会自动忽略 `null` 值的条件,但是在实际开发中,有的开发者希望除了自动忽略 `null`
值以外,还可以自动忽略其他值,比如 `空字符串` 等。

View File

@ -1,6 +1,34 @@
# MyBatis-Flex ChangeLog
## v1.5.7 20230812:
- 新增QueryWrapper 添加对 delete 和 update 的 left join 支持
- 新增RelationManager.addIgnoreRelations() 添加对 lambda 的支持
- 新增:添加 QueryColumnBehavior 用于自定义 QueryColumn 的某些行为特征
- 新增typeHandler 添加对泛型自动支持的功能
- 新增:多数据源新增对 Seata 分布式事务的支持,感谢 @lifejwang11
- 新增:添加对 Kotlin 的扩展支持,感谢 @kamo-sama
- 新增:添加 saveOrUpdateBatch 方法的支持,感谢 @Suomm
- 新增QueryModel 提供 as 方法的支持,感谢 @Suomm
- 新增:逻辑删除、乐观锁、多租户添加全局默认自动配置的功能,感谢 @Suomm
- 优化:移除 flex 自动把 id 属性设置为主键的功能
- 优化:重构链式调用的方法,统一链式调用和 ActiveRecord 的 API感谢 @Suomm
- 优化UpdateChian 支持设置 left join 的表数据的支持,感谢 @Suomm
- 修复db2 方言的 KeywordWrap 错误的问题
- 修复:在某些场景下 count 查询没有被替换的问题,感谢 @Suomm
- 修复QueryWrapper 的 or(consumer, condition) 方法逻辑错误,感谢 @Suomm
- 修复QueryColumn 由于 Predicate 没有类型约束可能导致类型转换异常的问题,感谢 @Suomm
- 修复OSGI 环境下Lambda 通过 ClassLoader 获取不到类的问题,感谢 @2han9wen71an
- 文档:更新视频教程的文档链接
- 文档:添加 SpringBoot 最低版本的说明文档,感谢 @Suomm
- 文档Seata 分布式事务的相关文档,感谢 @lifejwang11
- 文档增加了使用gradle构建时的文档说明感谢 @CloudPlayer
- 文档增加了在Kotlin中使用注解处理器的说明感谢 @CloudPlayer
- 文档:常见问题添加代码生成器获取不到注释说明,感谢 @Suomm
- 文档:常见问题添加 Spring Devtools 造成的类转换异常的相关文档
- 文档:常见问题添加 Nacos 集成启动出错的相关文档
## v1.5.6 20230804:
- 新增:代码生成器重构并新增对 Solon 框架的代码生成功能,感谢 @Suomm

View File

@ -224,8 +224,14 @@ public void purchase(String userId, String commodityCode, int orderCount) {
> 的官方示例快速开始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`
在使用 Seata 分布式事务时,请注意添加 Seata 的相关 Maven 依赖,例如:
3.如果是 SpringBoot 项目需要引入相关 Maven 依赖,例如:
```xml
<dependency>
@ -234,3 +240,7 @@ public void purchase(String userId, String commodityCode, int orderCount) {
<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 结合。

View File

@ -1,5 +1,7 @@
# 常见问题
[[toc]]
## MyBatis-Flex 没有启动或者启动出错怎么办?
正常情况下MyBatis-Flex 在启动时,会在控制台打印如下 Banner 信息,包含版本与官方网址,如果在项目启动中没有发现 MyBatis-Flex 的 Banner 打印,那就说明 MyBatis-Flex 没有被正常加载。
@ -21,6 +23,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-项目-启动报错-java-lang-classnotfoundexception-org-springframework-transaction-transactionmanager) 获取详细信息。
## 示例中的 AccountMapper 和 "ACCOUNT" 在哪里,报错了。
@ -62,6 +65,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 依赖。
@ -88,6 +96,18 @@ SpringBoot v3.x 添加 hikariCP 的内容如下:
> 如果使用的是 druid 数据库连接池,则需要添加数据源类型的配置 `spring.datasource.type=com.alibaba.druid.pool.DruidDataSource`
## SpringBoot 项目中出现 class "com.xxx" cannot be cast class "com.xxx" 的错误
这个问题是由于 Spring 的 devtools 热加载引起的,可以在项目的 `resources/META-INF`
目录下创建一个名为 `spring-devtools.properties` 的配置文件,配置内容如下:
```properties
restart.include.mapper=/mapper-[\\w-\\.].jar
restart.include.pagehelper=/pagehelper-[\\w-\\.].jar
restart.include.mybatis-flex=/mybatis-flex-[\\w-\\.]+jar
```
相关文档参考 Spring 的官方网站https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using.devtools.restart.customizing-the-classload
## java.sql.SQLException: No value specified for parameter x
出现这个问题,原因是 MyBatis-Flex 未能正常启动SQL 执行没有经过 MyBatis-Flex 导致的。其直接是因为和其他第三方增强框架整合使用了,
比如和 MyBatis-Plus、或者 PageHelper 等整合造成的。
@ -161,13 +181,29 @@ spring:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>版本号</version>
<version>5.3.3</version>
</dependency>
```
解决方案https://gitee.com/mybatis-flex/mybatis-flex/issues/I71AUE
## 代码生成器获取不到注释
如果是 MySQL 数据库的话可能是因为数据库版本太低解决办法MySQL 5.* 需要在 jdbcUrl 设置参数 `useInformationSchema=true` 才能获取到注释。
例如:`jdbc:mysql://127.0.0.1:3306/mybatis-flex?characterEncoding=UTF-8&useInformationSchema=true`
## 与 Nacos 集成时出错,无法正常启动 MyBatis-Flex
一般请看下是缺少 Nacos 的相关 Maven注意添加如下的 Nacos 依赖:
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0</version>
</dependency>
```
## 如何自定义 MyBatis 的 Configuration?

View File

@ -51,7 +51,7 @@ VALUES (1, '张三', 18, '2020-01-11'),
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>

View File

@ -12,12 +12,12 @@
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-core</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
<scope>provided</scope>
</dependency>
```
@ -28,12 +28,12 @@
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
<scope>provided</scope>
</dependency>
``````
@ -44,12 +44,12 @@
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
<scope>provided</scope>
</dependency>
```
@ -60,7 +60,7 @@
参考:[APT 设置-和 Lombok、Mapstruct 整合](../others/apt.md)
> 在Kotlin中使用时请参考[在Kotlin中使用注解处理器](../kotlin/kapt.md)
> 在Kotlin中使用时请参考[在Kotlin中使用注解处理器](../others/kapt.md)
```xml
<plugin>
@ -72,7 +72,7 @@
<path>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
</path>
</annotationProcessorPaths>
</configuration>

View File

@ -220,7 +220,7 @@ pom.xml 添加 `annotationProcessorPaths` 配置,
```
dependencies {
...
annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:<version>1.5.6</version>'
annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:<version>1.5.7</version>'
}
```

View File

@ -10,7 +10,7 @@
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-codegen</artifactId>
<version>1.5.6</version>
<version>1.5.7</version>
</dependency>
```

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -87,6 +87,30 @@ public class #(table.buildServiceImplClassName()) extends #(serviceImplConfig.bu
return super.getOneAs(query, asType);
}
@Override
@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
public Object getObj(QueryWrapper query) {
return super.getObj(query);
}
@Override
@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
public <R> R getObjAs(QueryWrapper query, Class<R> asType) {
return super.getObjAs(query, asType);
}
@Override
@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
public List<Object> objList(QueryWrapper query) {
return super.objList(query);
}
@Override
@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
public <R> List<R> objListAs(QueryWrapper query, Class<R> asType) {
return super.objListAs(query, asType);
}
@Override
@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
public List<#(entityClassName)> list(QueryWrapper query) {

View File

@ -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();

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -17,6 +17,9 @@ package com.mybatisflex.core;
/**
* Mybatis-Flex 可能用到的静态常量
*
* @author michael
* @author 王帅
*/
public class FlexConsts {
@ -24,9 +27,8 @@ public class FlexConsts {
}
public static final String NAME = "MyBatis-Flex";
public static final String VERSION = "1.5.6";
public static final String VERSION = "1.5.7";
public static final String DEFAULT_PRIMARY_FIELD = "id";
public static final String SQL = "$$sql";
public static final String SQL_ARGS = "$$sql_args";

View File

@ -88,6 +88,21 @@ public class FlexGlobalConfig {
*/
private int defaultRelationQueryDepth = 2;
/**
* 默认的逻辑删除字段允许设置 {@code null} 忽略匹配
*/
private String logicDeleteColumn = "del_flag";
/**
* 默认的多租户字段允许设置 {@code null} 忽略匹配
*/
private String tenantColumn = "tenant_id";
/**
* 默认的乐观锁字段允许设置 {@code null} 忽略匹配
*/
private String versionColumn = "version";
public boolean isPrintBanner() {
return printBanner;
}
@ -337,6 +352,30 @@ public class FlexGlobalConfig {
this.defaultRelationQueryDepth = defaultRelationQueryDepth;
}
public String getLogicDeleteColumn() {
return logicDeleteColumn;
}
public void setLogicDeleteColumn(String logicDeleteColumn) {
this.logicDeleteColumn = logicDeleteColumn;
}
public String getTenantColumn() {
return tenantColumn;
}
public void setTenantColumn(String tenantColumn) {
this.tenantColumn = tenantColumn;
}
public String getVersionColumn() {
return versionColumn;
}
public void setVersionColumn(String versionColumn) {
this.versionColumn = versionColumn;
}
public FlexDataSource getDataSource() {
return (FlexDataSource) getConfiguration().getEnvironment().getDataSource();
}

View File

@ -44,11 +44,20 @@ public abstract class QueryModel<T extends QueryModel<T>> {
protected QueryWrapper queryWrapper() {
if (queryWrapper == null) {
queryWrapper = QueryWrapper.create();
TableInfo tableInfo = TableInfoFactory.ofEntityClass(getClass());
QueryTable queryTable = new QueryTable();
queryTable.setSchema(tableInfo.getSchema());
queryTable.setName(tableInfo.getTableName());
queryWrapper = QueryWrapper.create().from(queryTable);
}
return queryWrapper;
}
public T as(String alias) {
queryWrapper().as(alias);
return (T) this;
}
public T select() {
return (T) this;
}

View File

@ -22,6 +22,7 @@ import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
import java.util.Collection;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
/**
@ -49,7 +50,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R eq(Object value, Predicate<T> when) {
public <T> R eq(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.eq(value, when), connector);
}
@ -60,8 +61,15 @@ public class WhereBuilder<R extends QueryModel<R>> {
return eq(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> R eq(LambdaGetter<T> value, Predicate<T> when) {
return eq(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.eq(LambdaUtil.getQueryColumn(value)).when(when), connector);
}
return queryModel;
}
public R ne(Object value) {
@ -71,7 +79,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R ne(Object value, Predicate<T> when) {
public <T> R ne(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.ne(value, when), connector);
}
@ -82,8 +90,15 @@ public class WhereBuilder<R extends QueryModel<R>> {
return ne(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> R ne(LambdaGetter<T> value, Predicate<T> when) {
return ne(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.ne(LambdaUtil.getQueryColumn(value)).when(when), connector);
}
return queryModel;
}
public R like(Object value) {
@ -93,7 +108,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R like(Object value, Predicate<T> when) {
public <T> R like(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.like(value, when), connector);
}
@ -107,7 +122,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R likeLeft(Object value, Predicate<T> when) {
public <T> R likeLeft(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.likeLeft(value, when), connector);
}
@ -121,7 +136,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R likeRight(Object value, Predicate<T> when) {
public <T> R likeRight(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.likeRight(value, when), connector);
}
@ -135,7 +150,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R gt(Object value, Predicate<T> when) {
public <T> R gt(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.gt(value, when), connector);
}
@ -146,8 +161,15 @@ public class WhereBuilder<R extends QueryModel<R>> {
return gt(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> R gt(LambdaGetter<T> value, Predicate<T> when) {
return gt(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.gt(LambdaUtil.getQueryColumn(value)).when(when), connector);
}
return queryModel;
}
public R ge(Object value) {
@ -157,7 +179,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R ge(Object value, Predicate<T> when) {
public <T> R ge(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.ge(value, when), connector);
}
@ -168,8 +190,15 @@ public class WhereBuilder<R extends QueryModel<R>> {
return ge(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> R ge(LambdaGetter<T> value, Predicate<T> when) {
return ge(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.ge(LambdaUtil.getQueryColumn(value)).when(when), connector);
}
return queryModel;
}
public R lt(Object value) {
@ -179,7 +208,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R lt(Object value, Predicate<T> when) {
public <T> R lt(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.lt(value, when), connector);
}
@ -190,8 +219,15 @@ public class WhereBuilder<R extends QueryModel<R>> {
return lt(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> R lt(LambdaGetter<T> value, Predicate<T> when) {
return lt(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.lt(LambdaUtil.getQueryColumn(value)).when(when), connector);
}
return queryModel;
}
public R le(Object value) {
@ -201,7 +237,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R le(Object value, Predicate<T> when) {
public <T> R le(T value, Predicate<T> when) {
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.le(value, when), connector);
}
@ -212,8 +248,15 @@ public class WhereBuilder<R extends QueryModel<R>> {
return le(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> R le(LambdaGetter<T> value, Predicate<T> when) {
return le(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.le(LambdaUtil.getQueryColumn(value)).when(when), connector);
}
return queryModel;
}
public R isNull() {
@ -221,6 +264,10 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> R isNull(Predicate<T> when) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.isNull(when), connector);
return queryModel;
@ -231,6 +278,10 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> R isNotNull(Predicate<T> when) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.isNotNull(when), connector);
return queryModel;
@ -243,7 +294,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R in(Object[] arrays, Predicate<T> when) {
public <T> R in(T[] arrays, Predicate<T[]> when) {
//忽略 QueryWrapper.in("name", null) 的情况
if (arrays != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.in(arrays, when), connector);
@ -258,6 +309,10 @@ public class WhereBuilder<R extends QueryModel<R>> {
return this.queryModel;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> R in(R queryModel, Predicate<T> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.in(queryModel, when), connector);
@ -272,7 +327,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R in(Collection<?> collection, Predicate<T> when) {
public <T extends Collection<?>> R in(T collection, Predicate<T> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.in(collection, when), connector);
}
@ -286,7 +341,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R notIn(Object[] arrays, Predicate<T> when) {
public <T> R notIn(T[] arrays, Predicate<T[]> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.notIn(arrays, when), connector);
}
@ -300,7 +355,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R notIn(Collection<?> collection, Predicate<T> when) {
public <T extends Collection<?>> R notIn(T collection, Predicate<T> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.notIn(collection, when), connector);
}
@ -314,6 +369,10 @@ public class WhereBuilder<R extends QueryModel<R>> {
return this.queryModel;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> R notIn(R queryModel, Predicate<T> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.notIn(queryModel, when), connector);
@ -328,7 +387,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R between(Object start, Object end, Predicate<T> when) {
public <S, E> R between(S start, E end, BiPredicate<S, E> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.between(start, end, when), connector);
}
@ -342,7 +401,7 @@ public class WhereBuilder<R extends QueryModel<R>> {
return queryModel;
}
public <T> R notBetween(Object start, Object end, Predicate<T> when) {
public <S, E> R notBetween(S start, E end, BiPredicate<S, E> when) {
if (queryModel != null) {
CPI.addWhereQueryCondition(queryModel.queryWrapper(), queryColumn.notBetween(start, end, when), connector);
}

View File

@ -103,12 +103,13 @@ public class DialectFactory {
case GBASE:
case OSCAR:
case XUGU:
case CLICK_HOUSE:
case OCEAN_BASE:
case CUBRID:
case GOLDILOCKS:
case CSIIDB:
return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.MYSQL);
case CLICK_HOUSE:
return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.MYSQL);
case DM:
return new DmDialect();
case ORACLE:
@ -134,13 +135,13 @@ public class DialectFactory {
return new OracleDialect(LimitOffsetProcessor.DERBY);
case FIREBIRD:
case DB2:
return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.DERBY);
return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.DERBY);
case SQLSERVER:
return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER);
case SQLSERVER_2005:
return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER_2005);
case INFORMIX:
return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.INFORMIX);
return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.INFORMIX);
case SINODB:
return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SINODB);
case SYBASE:

View File

@ -242,7 +242,7 @@ public class CommonsDialectImpl implements IDialect {
@Override
public String forUpdateByQuery(QueryWrapper queryWrapper, Row row) {
StringBuilder sql = new StringBuilder();
StringBuilder sqlBuilder = new StringBuilder();
Set<String> modifyAttrs = RowCPI.getModifyAttrs(row);
Map<String, RawValue> rawValueMap = RowCPI.getRawValueMap(row);
@ -254,30 +254,39 @@ public class CommonsDialectImpl implements IDialect {
//fix: support schema
QueryTable queryTable = queryTables.get(0);
sql.append(UPDATE).append(queryTable.toSql(this)).append(SET);
sqlBuilder.append(UPDATE).append(queryTable.toSql(this)).append(SET);
int index = 0;
for (String modifyAttr : modifyAttrs) {
if (index > 0) {
sql.append(DELIMITER);
sqlBuilder.append(DELIMITER);
}
sql.append(wrap(modifyAttr));
sqlBuilder.append(wrap(modifyAttr));
if (rawValueMap.containsKey(modifyAttr)) {
sql.append(EQUALS).append(rawValueMap.get(modifyAttr).toSql(this));
sqlBuilder.append(EQUALS).append(rawValueMap.get(modifyAttr).toSql(this));
} else {
sql.append(EQUALS_PLACEHOLDER);
sqlBuilder.append(EQUALS_PLACEHOLDER);
}
index++;
}
String whereConditionSql = buildWhereConditionSql(queryWrapper);
if (StringUtil.isNotBlank(whereConditionSql)) {
sql.append(WHERE).append(whereConditionSql);
buildJoinSql(sqlBuilder, queryWrapper, queryTables);
buildWhereSql(sqlBuilder, queryWrapper, queryTables, false);
buildGroupBySql(sqlBuilder, queryWrapper, queryTables);
buildHavingSql(sqlBuilder, queryWrapper, queryTables);
//ignore orderBy and limit
buildOrderBySql(sqlBuilder, queryWrapper, queryTables);
Long limitRows = CPI.getLimitRows(queryWrapper);
Long limitOffset = CPI.getLimitOffset(queryWrapper);
if (limitRows != null || limitOffset != null) {
sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset);
}
return sql.toString();
return sqlBuilder.toString();
}
@Override
@ -473,8 +482,13 @@ public class CommonsDialectImpl implements IDialect {
buildHavingSql(sqlBuilder, queryWrapper, allTables);
//ignore orderBy and limit
//buildOrderBySql(sqlBuilder, queryWrapper)
//buildLimitSql(sqlBuilder, queryWrapper)
buildOrderBySql(sqlBuilder, queryWrapper, allTables);
Long limitRows = CPI.getLimitRows(queryWrapper);
Long limitOffset = CPI.getLimitOffset(queryWrapper);
if (limitRows != null || limitOffset != null) {
sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset);
}
List<String> endFragments = CPI.getEndFragments(queryWrapper);
if (CollectionUtil.isNotEmpty(endFragments)) {
@ -777,13 +791,19 @@ public class CommonsDialectImpl implements IDialect {
@Override
public String forUpdateEntityByQuery(TableInfo tableInfo, Object entity, boolean ignoreNulls, QueryWrapper queryWrapper) {
StringBuilder sql = new StringBuilder();
StringBuilder sqlBuilder = new StringBuilder();
Set<String> updateColumns = tableInfo.obtainUpdateColumns(entity, ignoreNulls, true);
Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity);
sql.append(UPDATE).append(forHint(CPI.getHint(queryWrapper)));
sql.append(tableInfo.getWrapSchemaAndTableName(this)).append(SET);
sqlBuilder.append(UPDATE).append(forHint(CPI.getHint(queryWrapper)));
sqlBuilder.append(tableInfo.getWrapSchemaAndTableName(this));
List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper);
buildJoinSql(sqlBuilder, queryWrapper, queryTables);
sqlBuilder.append(SET);
StringJoiner stringJoiner = new StringJoiner(DELIMITER);
@ -807,26 +827,40 @@ public class CommonsDialectImpl implements IDialect {
stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 ");
}
sql.append(stringJoiner);
sqlBuilder.append(stringJoiner);
String whereConditionSql = buildWhereConditionSql(queryWrapper);
buildWhereSql(sqlBuilder, queryWrapper, queryTables, false);
buildGroupBySql(sqlBuilder, queryWrapper, queryTables);
buildHavingSql(sqlBuilder, queryWrapper, queryTables);
//不允许全量更新
if (StringUtil.isBlank(whereConditionSql)) {
throw FlexExceptions.wrap(LocalizedFormats.UPDATE_OR_DELETE_NOT_ALLOW);
//ignore orderBy and limit
buildOrderBySql(sqlBuilder, queryWrapper, queryTables);
Long limitRows = CPI.getLimitRows(queryWrapper);
Long limitOffset = CPI.getLimitOffset(queryWrapper);
if (limitRows != null || limitOffset != null) {
sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset);
}
sql.append(WHERE).append(whereConditionSql);
// String whereConditionSql = buildWhereConditionSql(queryWrapper);
//
// //不允许全量更新
// if (StringUtil.isBlank(whereConditionSql)) {
// throw FlexExceptions.wrap(LocalizedFormats.UPDATE_OR_DELETE_NOT_ALLOW);
// }
//
// sql.append(WHERE).append(whereConditionSql);
List<String> endFragments = CPI.getEndFragments(queryWrapper);
if (CollectionUtil.isNotEmpty(endFragments)) {
for (String endFragment : endFragments) {
sql.append(BLANK).append(endFragment);
sqlBuilder.append(BLANK).append(endFragment);
}
}
return sql.toString();
return sqlBuilder.toString();
}
@ -973,16 +1007,19 @@ public class CommonsDialectImpl implements IDialect {
}
protected void buildJoinSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) {
protected boolean buildJoinSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) {
List<Join> joins = CPI.getJoins(queryWrapper);
boolean joinSuccess = false;
if (joins != null && !joins.isEmpty()) {
for (Join join : joins) {
if (!join.checkEffective()) {
continue;
}
sqlBuilder.append(join.toSql(queryTables, this));
joinSuccess = true;
}
}
return joinSuccess;
}

View File

@ -17,18 +17,38 @@ package com.mybatisflex.core.handler;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.TypeReference;
import java.lang.reflect.Type;
import java.util.Collection;
/**
* @author michael
*/
public class Fastjson2TypeHandler extends BaseJsonTypeHandler<Object> {
private final Class<?> propertyType;
private Class<?> genericType;
private Type type;
public Fastjson2TypeHandler(Class<?> type) {
this.propertyType = type;
public Fastjson2TypeHandler(Class<?> propertyType) {
this.propertyType = propertyType;
}
public Fastjson2TypeHandler(Class<?> propertyType, Class<?> genericType) {
this.propertyType = propertyType;
this.genericType = genericType;
this.type = TypeReference.collectionType((Class<? extends Collection>) propertyType, genericType);
}
@Override
protected Object parseJson(String json) {
return JSON.parseObject(json, propertyType);
if (genericType != null && Collection.class.isAssignableFrom(propertyType)) {
return JSON.parseObject(json, type);
} else {
return JSON.parseObject(json, propertyType);
}
}
@Override

View File

@ -18,17 +18,37 @@ package com.mybatisflex.core.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
/**
* @author michael
*/
public class FastjsonTypeHandler extends BaseJsonTypeHandler<Object> {
private final Class<?> propertyType;
private Class<?> genericType;
private Type type;
public FastjsonTypeHandler(Class<?> type) {
this.propertyType = type;
public FastjsonTypeHandler(Class<?> propertyType) {
this.propertyType = propertyType;
}
public FastjsonTypeHandler(Class<?> propertyType, Class<?> genericType) {
this.propertyType = propertyType;
this.genericType = genericType;
this.type = new ParameterizedTypeImpl(propertyType, genericType);
}
@Override
protected Object parseJson(String json) {
return JSON.parseObject(json, propertyType);
if (genericType != null && Collection.class.isAssignableFrom(propertyType)) {
return JSON.parseObject(json, type);
} else {
return JSON.parseObject(json, propertyType);
}
}
@Override
@ -37,4 +57,66 @@ public class FastjsonTypeHandler extends BaseJsonTypeHandler<Object> {
SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty);
}
public static class ParameterizedTypeImpl implements ParameterizedType {
private final Type[] actualTypeArguments;
private final Type ownerType;
private final Type rawType;
public ParameterizedTypeImpl(Type rawType, Type... actualTypeArguments) {
this.rawType = rawType;
this.actualTypeArguments = actualTypeArguments;
this.ownerType = null;
}
@Override
public Type[] getActualTypeArguments() {
return this.actualTypeArguments;
}
@Override
public Type getOwnerType() {
return this.ownerType;
}
@Override
public Type getRawType() {
return this.rawType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
ParameterizedTypeImpl that = (ParameterizedTypeImpl) o;
if (!Arrays.equals(this.actualTypeArguments, that.actualTypeArguments)) {
return false;
} else {
if (this.ownerType != null) {
if (this.ownerType.equals(that.ownerType)) {
return this.rawType != null ? this.rawType.equals(that.rawType) : that.rawType == null;
}
} else if (that.ownerType == null) {
return this.rawType != null ? this.rawType.equals(that.rawType) : that.rawType == null;
}
return false;
}
} else {
return false;
}
}
@Override
public int hashCode() {
int result = this.actualTypeArguments != null ? Arrays.hashCode(this.actualTypeArguments) : 0;
result = 31 * result + (this.ownerType != null ? this.ownerType.hashCode() : 0);
result = 31 * result + (this.rawType != null ? this.rawType.hashCode() : 0);
return result;
}
}
}

View File

@ -16,19 +16,34 @@
package com.mybatisflex.core.handler;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* @author michael
*/
public class GsonTypeHandler extends BaseJsonTypeHandler<Object> {
private static Gson gson;
private final Class<?> propertyType;
private Class<?> genericType;
public GsonTypeHandler(Class<?> type) {
this.propertyType = type;
public GsonTypeHandler(Class<?> propertyType) {
this.propertyType = propertyType;
}
public GsonTypeHandler(Class<?> propertyType, Class<?> genericType) {
this.propertyType = propertyType;
this.genericType = genericType;
}
@Override
protected Object parseJson(String json) {
return getGson().fromJson(json, propertyType);
if (genericType != null) {
TypeToken<?> typeToken = TypeToken.getParameterized(propertyType, genericType);
return getGson().fromJson(json, typeToken);
} else {
return getGson().fromJson(json, propertyType);
}
}
@Override

View File

@ -16,24 +16,40 @@
package com.mybatisflex.core.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybatisflex.core.exception.FlexExceptions;
import java.io.IOException;
import java.util.Collection;
/**
* @author michael
*/
public class JacksonTypeHandler extends BaseJsonTypeHandler<Object> {
private static ObjectMapper objectMapper;
private final Class<?> propertyType;
private Class<?> genericType;
private JavaType javaType;
public JacksonTypeHandler(Class<?> propertyType) {
this.propertyType = propertyType;
}
public JacksonTypeHandler(Class<?> propertyType, Class<?> genericType) {
this.propertyType = propertyType;
this.genericType = genericType;
}
@Override
protected Object parseJson(String json) {
try {
return getObjectMapper().readValue(json, propertyType);
if (genericType != null && Collection.class.isAssignableFrom(propertyType)) {
return getObjectMapper().readValue(json, getJavaType());
} else {
return getObjectMapper().readValue(json, propertyType);
}
} catch (IOException e) {
throw FlexExceptions.wrap(e, "Can not parseJson by JacksonTypeHandler: " + json);
}
@ -48,6 +64,14 @@ public class JacksonTypeHandler extends BaseJsonTypeHandler<Object> {
}
}
public JavaType getJavaType() {
if (javaType == null){
javaType = getObjectMapper().getTypeFactory().constructCollectionType((Class<? extends Collection>) propertyType, genericType);
}
return javaType;
}
public static ObjectMapper getObjectMapper() {
if (null == objectMapper) {
objectMapper = new ObjectMapper();

View File

@ -261,7 +261,9 @@ public class EntitySqlProvider {
FlexAssert.notNull(entity, "entity can not be null");
boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params);
QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
appendTableConditions(context,queryWrapper,false);
TableInfo tableInfo = ProviderUtil.getTableInfo(context);
@ -274,9 +276,13 @@ public class EntitySqlProvider {
//优先构建 sql再构建参数
String sql = DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, ignoreNulls, queryWrapper);
Object[] joinValueArray = CPI.getJoinValueArray(queryWrapper);
Object[] values = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, true);
Object[] queryParams = CPI.getValueArray(queryWrapper);
ProviderUtil.setSqlArgs(params, ArrayUtil.concat(values, queryParams));
Object[] queryParams = CPI.getConditionValueArray(queryWrapper);
Object[] paramValues = ArrayUtil.concat(joinValueArray,ArrayUtil.concat(values,queryParams));
ProviderUtil.setSqlArgs(params, paramValues);
return sql;
}

View File

@ -34,7 +34,15 @@ public class CPI {
}
public static Object[] getValueArray(QueryWrapper queryWrapper) {
return queryWrapper.getValueArray();
return queryWrapper.getAllValueArray();
}
public static Object[] getJoinValueArray(QueryWrapper queryWrapper) {
return queryWrapper.getJoinValueArray();
}
public static Object[] getConditionValueArray(QueryWrapper queryWrapper) {
return queryWrapper.getConditionValueArray();
}
public static List<QueryWrapper> getChildSelect(QueryWrapper queryWrapper) {

View File

@ -45,7 +45,9 @@ public class If {
* 查看某个对象是否为空支持数组集合map
*
* @param object
* @deprecated 无泛型 instanceof 判断
*/
@Deprecated
public static boolean notEmpty(Object object) {
if (object == null) {
return false;
@ -74,7 +76,9 @@ public class If {
* 查看某个对象是否为空数据 或者 null
*
* @param object
* @deprecated 无泛型 instanceof 判断
*/
@Deprecated
public static boolean isEmpty(Object object) {
return !notEmpty(object);
}

View File

@ -71,7 +71,7 @@ public class OperatorSelectCondition extends QueryCondition {
@Override
public Object getValue() {
return queryWrapper.getValueArray();
return queryWrapper.getAllValueArray();
}
@Override

View File

@ -24,6 +24,7 @@ import com.mybatisflex.core.util.*;
import java.util.Collection;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
/**
@ -147,11 +148,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
}
public <T> QueryCondition eq(Object value, Predicate<T> fn) {
public <T> QueryCondition eq(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.EQUALS, value).when(fn);
return QueryCondition.create(this, SqlConsts.EQUALS, value).when(fn.test(value));
}
@ -167,11 +168,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value);
}
public <T> QueryCondition ne(Object value, Predicate<T> fn) {
public <T> QueryCondition ne(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value).when(fn);
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value).when(fn.test(value));
}
@ -187,11 +188,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%");
}
public <T> QueryCondition like(Object value, Predicate<T> fn) {
public <T> QueryCondition like(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%").when(fn);
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%").when(fn.test(value));
}
@ -202,11 +203,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.LIKE, value + "%");
}
public <T> QueryCondition likeLeft(Object value, Predicate<T> fn) {
public <T> QueryCondition likeLeft(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.LIKE, value + "%").when(fn);
return QueryCondition.create(this, SqlConsts.LIKE, value + "%").when(fn.test(value));
}
@ -217,11 +218,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value);
}
public <T> QueryCondition likeRight(Object value, Predicate<T> fn) {
public <T> QueryCondition likeRight(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value).when(fn);
return QueryCondition.create(this, SqlConsts.LIKE, "%" + value).when(fn.test(value));
}
@ -232,11 +233,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.LIKE, value);
}
public <T> QueryCondition likeRaw(Object value, Predicate<T> fn) {
public <T> QueryCondition likeRaw(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.LIKE, value).when(fn);
return QueryCondition.create(this, SqlConsts.LIKE, value).when(fn.test(value));
}
@ -252,11 +253,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value + "%");
}
public <T> QueryCondition notLike(Object value, Predicate<T> fn) {
public <T> QueryCondition notLike(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value + "%").when(fn);
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value + "%").when(fn.test(value));
}
@ -267,11 +268,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_LIKE, value + "%");
}
public <T> QueryCondition notLikeLeft(Object value, Predicate<T> fn) {
public <T> QueryCondition notLikeLeft(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.NOT_LIKE, value + "%").when(fn);
return QueryCondition.create(this, SqlConsts.NOT_LIKE, value + "%").when(fn.test(value));
}
@ -282,11 +283,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value);
}
public <T> QueryCondition notLikeRight(Object value, Predicate<T> fn) {
public <T> QueryCondition notLikeRight(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value).when(fn);
return QueryCondition.create(this, SqlConsts.NOT_LIKE, "%" + value).when(fn.test(value));
}
@ -302,11 +303,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.GT, value);
}
public <T> QueryCondition gt(Object value, Predicate<T> fn) {
public <T> QueryCondition gt(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.GT, value).when(fn);
return QueryCondition.create(this, SqlConsts.GT, value).when(fn.test(value));
}
/**
@ -321,11 +322,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.GE, value);
}
public <T> QueryCondition ge(Object value, Predicate<T> fn) {
public <T> QueryCondition ge(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.GE, value).when(fn);
return QueryCondition.create(this, SqlConsts.GE, value).when(fn.test(value));
}
/**
@ -340,11 +341,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.LT, value);
}
public <T> QueryCondition lt(Object value, Predicate<T> fn) {
public <T> QueryCondition lt(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.LT, value).when(fn);
return QueryCondition.create(this, SqlConsts.LT, value).when(fn.test(value));
}
/**
@ -359,11 +360,11 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.LE, value);
}
public <T> QueryCondition le(Object value, Predicate<T> fn) {
public <T> QueryCondition le(T value, Predicate<T> fn) {
if (value == null || QueryColumnBehavior.shouldIgnoreValue(value)) {
return QueryCondition.createEmpty();
}
return QueryCondition.create(this, SqlConsts.LE, value).when(fn);
return QueryCondition.create(this, SqlConsts.LE, value).when(fn.test(value));
}
@ -376,6 +377,10 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.IS_NULL, null);
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> QueryCondition isNull(Predicate<T> fn) {
return QueryCondition.create(this, SqlConsts.IS_NULL, null).when(fn);
}
@ -390,6 +395,10 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.IS_NOT_NULL, null);
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> QueryCondition isNotNull(Predicate<T> fn) {
return QueryCondition.create(this, SqlConsts.IS_NOT_NULL, null).when(fn);
}
@ -415,7 +424,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
}
public <T> QueryCondition in(Object[] arrays, Predicate<T> fn) {
public <T> QueryCondition in(T[] arrays, Predicate<T[]> fn) {
//忽略 QueryWrapper.in("name", null) 的情况
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null) || QueryColumnBehavior.shouldIgnoreValue(arrays)) {
return QueryCondition.createEmpty();
@ -425,7 +434,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.EQUALS, arrays[0]);
}
return QueryCondition.create(this, SqlConsts.IN, arrays).when(fn);
return QueryCondition.create(this, SqlConsts.IN, arrays).when(fn.test(arrays));
}
/**
@ -442,6 +451,10 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> QueryCondition in(QueryWrapper queryWrapper, Predicate<T> fn) {
if (queryWrapper == null || QueryColumnBehavior.shouldIgnoreValue(queryWrapper)) {
return QueryCondition.createEmpty();
@ -457,17 +470,17 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
* @return QueryCondition
*/
public QueryCondition in(Collection<?> collection) {
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
return in(collection.toArray());
if (collection == null || collection.isEmpty() || QueryColumnBehavior.shouldIgnoreValue(collection)) {
return QueryCondition.createEmpty();
}
return QueryCondition.createEmpty();
return in(collection.toArray());
}
public <T> QueryCondition in(Collection<?> collection, Predicate<T> fn) {
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
return in(collection.toArray(), fn);
public <T extends Collection<?>> QueryCondition in(T collection, Predicate<T> fn) {
if (collection == null || collection.isEmpty() || QueryColumnBehavior.shouldIgnoreValue(collection)) {
return QueryCondition.createEmpty();
}
return QueryCondition.createEmpty();
return in(collection.toArray()).when(fn.test(collection));
}
/**
@ -489,7 +502,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_IN, arrays);
}
public <T> QueryCondition notIn(Object[] arrays, Predicate<T> fn) {
public <T> QueryCondition notIn(T[] arrays, Predicate<T[]> fn) {
//忽略 QueryWrapper.notIn("name", null) 的情况
if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null) || QueryColumnBehavior.shouldIgnoreValue(arrays)) {
return QueryCondition.createEmpty();
@ -499,7 +512,7 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_EQUALS, arrays[0]);
}
return QueryCondition.create(this, SqlConsts.NOT_IN, arrays).when(fn);
return QueryCondition.create(this, SqlConsts.NOT_IN, arrays).when(fn.test(arrays));
}
@ -510,17 +523,17 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
* @return QueryCondition
*/
public QueryCondition notIn(Collection<?> collection) {
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
return notIn(collection.toArray());
if (collection == null || collection.isEmpty() || QueryColumnBehavior.shouldIgnoreValue(collection)) {
return QueryCondition.createEmpty();
}
return QueryCondition.createEmpty();
return notIn(collection.toArray());
}
public <T> QueryCondition notIn(Collection<?> collection, Predicate<T> fn) {
if (collection != null && !collection.isEmpty() && !QueryColumnBehavior.shouldIgnoreValue(collection)) {
return notIn(collection.toArray(), fn);
public <T extends Collection<?>> QueryCondition notIn(T collection, Predicate<T> fn) {
if (collection == null || collection.isEmpty() || QueryColumnBehavior.shouldIgnoreValue(collection)) {
return QueryCondition.createEmpty();
}
return QueryCondition.createEmpty();
return notIn(collection.toArray()).when(fn.test(collection));
}
/**
@ -536,6 +549,10 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> QueryCondition notIn(QueryWrapper queryWrapper, Predicate<T> fn) {
if (queryWrapper == null || QueryColumnBehavior.shouldIgnoreValue(queryWrapper)) {
return QueryCondition.createEmpty();
@ -554,8 +571,8 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.BETWEEN, new Object[]{start, end});
}
public <T> QueryCondition between(Object start, Object end, Predicate<T> fn) {
return QueryCondition.create(this, SqlConsts.BETWEEN, new Object[]{start, end}).when(fn);
public <S, E> QueryCondition between(S start, E end, BiPredicate<S, E> fn) {
return QueryCondition.create(this, SqlConsts.BETWEEN, new Object[]{start, end}).when(fn.test(start, end));
}
@ -569,8 +586,8 @@ public class QueryColumn implements CloneSupport<QueryColumn> {
return QueryCondition.create(this, SqlConsts.NOT_BETWEEN, new Object[]{start, end});
}
public <T> QueryCondition notBetween(Object start, Object end, Predicate<T> fn) {
return QueryCondition.create(this, SqlConsts.NOT_BETWEEN, new Object[]{start, end}).when(fn);
public <S, E> QueryCondition notBetween(S start, E end, BiPredicate<S, E> fn) {
return QueryCondition.create(this, SqlConsts.NOT_BETWEEN, new Object[]{start, end}).when(fn.test(start, end));
}

View File

@ -24,8 +24,8 @@ import com.mybatisflex.core.util.ObjectUtil;
import java.lang.reflect.Array;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class QueryCondition implements CloneSupport<QueryCondition> {
@ -96,17 +96,44 @@ public class QueryCondition implements CloneSupport<QueryCondition> {
this.logic = logic;
}
/**
* 动态条件构造
*
* @param effective 是否启用该条件
* @return {@link QueryCondition}
*/
public QueryCondition when(boolean effective) {
this.effective = effective;
return this;
}
public void when(Supplier<Boolean> fn) {
Boolean effective = fn.get();
this.effective = (effective != null && effective);
/**
* 动态条件构造
*
* @param fn 是否启用该条件
* @return {@link QueryCondition}
*/
public QueryCondition when(BooleanSupplier fn) {
this.effective = fn.getAsBoolean();
return this;
}
/**
* <p>动态条件构造
*
* <p>推荐将 {@link Predicate} 推断写在填写的值的后面以确保泛型对应例如
* <pre>{@code
* ACCOUNT.ID.in(idList, CollectionUtil::isNotEmpty);
* }</pre>
*
* @see #when(boolean)
* @see #when(BooleanSupplier)
* @deprecated 由于 {@link QueryCondition} 中属性 {@link #value} 的类型为 Object
* 类型没有使用泛型所以该方法泛型推断可能会出现问题
*/
@Deprecated
@SuppressWarnings("unchecked")
public <T> QueryCondition when(Predicate<T> fn) {
Object val = this.value;
if ((SqlConsts.LIKE.equals(logic) || SqlConsts.NOT_LIKE.equals(logic))

View File

@ -19,6 +19,7 @@ import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
import java.util.Collection;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
@ -47,7 +48,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
}
public <T> Wrapper eq(Object value, Predicate<T> when) {
public <T> Wrapper eq(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.eq(value, when), connector);
}
@ -59,9 +60,15 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return eq(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> Wrapper eq(LambdaGetter<T> value, Predicate<T> when) {
return eq(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.eq(value).when(when), connector);
}
return queryWrapper;
}
@ -77,7 +84,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper ne(Object value, Predicate<T> when) {
public <T> Wrapper ne(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.ne(value, when), connector);
}
@ -89,8 +96,15 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> Wrapper ne(LambdaGetter<T> value, Predicate<T> when) {
return ne(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.ne(value).when(when), connector);
}
return queryWrapper;
}
@ -106,7 +120,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper like(Object value, Predicate<T> when) {
public <T> Wrapper like(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.like(value, when), connector);
}
@ -121,7 +135,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper likeLeft(Object value, Predicate<T> when) {
public <T> Wrapper likeLeft(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.likeLeft(value, when), connector);
}
@ -136,7 +150,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper likeRight(Object value, Predicate<T> when) {
public <T> Wrapper likeRight(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.likeRight(value, when), connector);
}
@ -155,7 +169,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper gt(Object value, Predicate<T> when) {
public <T> Wrapper gt(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.gt(value, when), connector);
}
@ -166,9 +180,15 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return gt(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> Wrapper gt(LambdaGetter<T> value, Predicate<T> when) {
return gt(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.gt(value).when(when), connector);
}
return queryWrapper;
}
@ -184,7 +204,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper ge(Object value, Predicate<T> when) {
public <T> Wrapper ge(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.ge(value, when), connector);
}
@ -195,9 +215,15 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return ge(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> Wrapper ge(LambdaGetter<T> value, Predicate<T> when) {
return ge(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.ge(value).when(when), connector);
}
return queryWrapper;
}
/**
@ -212,7 +238,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper lt(Object value, Predicate<T> when) {
public <T> Wrapper lt(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.lt(value, when), connector);
}
@ -223,9 +249,15 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return lt(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> Wrapper lt(LambdaGetter<T> value, Predicate<T> when) {
return lt(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.lt(value).when(when), connector);
}
return queryWrapper;
}
/**
@ -241,7 +273,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
}
public <T> Wrapper le(Object value, Predicate<T> when) {
public <T> Wrapper le(T value, Predicate<T> when) {
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.le(value, when), connector);
}
@ -252,9 +284,15 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return le(LambdaUtil.getQueryColumn(value));
}
/**
* @deprecated {@link Predicate} 泛型参数无效
*/
@Deprecated
public <T> Wrapper le(LambdaGetter<T> value, Predicate<T> when) {
return le(LambdaUtil.getQueryColumn(value), when);
if (value != null) {
queryWrapper.addWhereQueryCondition(queryColumn.le(value).when(when), connector);
}
return queryWrapper;
}
@ -268,6 +306,10 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> Wrapper isNull(Predicate<T> when) {
queryWrapper.addWhereQueryCondition(queryColumn.isNull(when), connector);
return queryWrapper;
@ -284,6 +326,10 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> Wrapper isNotNull(Predicate<T> when) {
queryWrapper.addWhereQueryCondition(queryColumn.isNotNull(when), connector);
return queryWrapper;
@ -303,7 +349,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper in(Object[] arrays, Predicate<T> when) {
public <T> Wrapper in(T[] arrays, Predicate<T[]> when) {
//忽略 QueryWrapper.in("name", null) 的情况
if (arrays != null) {
queryWrapper.addWhereQueryCondition(queryColumn.in(arrays, when), connector);
@ -324,6 +370,10 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return this.queryWrapper;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> Wrapper in(QueryWrapper queryWrapper, Predicate<T> when) {
if (queryWrapper != null) {
this.queryWrapper.addWhereQueryCondition(queryColumn.in(queryWrapper, when), connector);
@ -345,7 +395,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper in(Collection<?> collection, Predicate<T> when) {
public <T extends Collection<?>> Wrapper in(T collection, Predicate<T> when) {
if (queryWrapper != null) {
queryWrapper.addWhereQueryCondition(queryColumn.in(collection, when), connector);
}
@ -365,7 +415,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper notIn(Object[] arrays, Predicate<T> when) {
public <T> Wrapper notIn(T[] arrays, Predicate<T[]> when) {
if (queryWrapper != null) {
queryWrapper.addWhereQueryCondition(queryColumn.notIn(arrays, when), connector);
}
@ -386,7 +436,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper notIn(Collection<?> collection, Predicate<T> when) {
public <T extends Collection<?>> Wrapper notIn(T collection, Predicate<T> when) {
if (queryWrapper != null) {
queryWrapper.addWhereQueryCondition(queryColumn.notIn(collection, when), connector);
}
@ -405,6 +455,10 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return this.queryWrapper;
}
/**
* @deprecated 无法推断泛型
*/
@Deprecated
public <T> Wrapper notIn(QueryWrapper queryWrapper, Predicate<T> when) {
if (queryWrapper != null) {
this.queryWrapper.addWhereQueryCondition(queryColumn.notIn(queryWrapper, when), connector);
@ -427,7 +481,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
}
public <T> Wrapper between(Object start, Object end, Predicate<T> when) {
public <S, E> Wrapper between(S start, E end, BiPredicate<S, E> when) {
if (queryWrapper != null) {
queryWrapper.addWhereQueryCondition(queryColumn.between(start, end, when), connector);
}
@ -448,7 +502,7 @@ public class QueryConditionBuilder<Wrapper extends QueryWrapper> {
return queryWrapper;
}
public <T> Wrapper notBetween(Object start, Object end, Predicate<T> when) {
public <S, E> Wrapper notBetween(S start, E end, BiPredicate<S, E> when) {
if (queryWrapper != null) {
queryWrapper.addWhereQueryCondition(queryColumn.notBetween(start, end, when), connector);
}

View File

@ -291,7 +291,7 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
}
public QueryWrapper or(Consumer<QueryWrapper> consumer, boolean condition) {
if (condition) {
if (!condition) {
return this;
}
QueryWrapper newWrapper = new QueryWrapper();
@ -692,7 +692,7 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
* 获取 queryWrapper 的参数
* 在构建 sql 的时候需要保证 where having 的前面
*/
Object[] getValueArray() {
Object[] getAllValueArray() {
List<Object> withValues = null;
if (with != null) {
@ -770,7 +770,7 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
if (CollectionUtil.isNotEmpty(unions)) {
for (UnionWrapper union : unions) {
QueryWrapper queryWrapper = union.getQueryWrapper();
paramValues = ArrayUtil.concat(paramValues, queryWrapper.getValueArray());
paramValues = ArrayUtil.concat(paramValues, queryWrapper.getAllValueArray());
}
}
@ -783,6 +783,67 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
return returnValues;
}
/**
* 获取 queryWrapper 的参数
* 在构建 sql 的时候需要保证 where having 的前面
*/
Object[] getJoinValueArray() {
//join 子查询的参数left join (select ...)
List<Object> joinValues = null;
List<Join> joins = getJoins();
if (CollectionUtil.isNotEmpty(joins)) {
for (Join join : joins) {
QueryTable joinTable = join.getQueryTable();
Object[] valueArray = joinTable.getValueArray();
if (valueArray.length > 0) {
if (joinValues == null) {
joinValues = new ArrayList<>(valueArray.length);
}
joinValues.addAll(Arrays.asList(valueArray));
}
QueryCondition onCondition = join.getOnCondition();
Object[] values = WrapperUtil.getValues(onCondition);
if (values.length > 0) {
if (joinValues == null) {
joinValues = new ArrayList<>(values.length);
}
joinValues.addAll(Arrays.asList(values));
}
}
}
return joinValues == null ? FlexConsts.EMPTY_ARRAY : joinValues.toArray();
}
/**
* 获取 queryWrapper 的参数
* 在构建 sql 的时候需要保证 where having 的前面
*/
Object[] getConditionValueArray() {
//where 参数
Object[] whereValues = WrapperUtil.getValues(whereQueryCondition);
//having 参数
Object[] havingValues = WrapperUtil.getValues(havingQueryCondition);
Object[] paramValues = ArrayUtil.concat(whereValues, havingValues);
//unions 参数
if (CollectionUtil.isNotEmpty(unions)) {
for (UnionWrapper union : unions) {
QueryWrapper queryWrapper = union.getQueryWrapper();
paramValues = ArrayUtil.concat(paramValues, queryWrapper.getAllValueArray());
}
}
return paramValues;
}
List<QueryWrapper> getChildSelect() {
List<QueryWrapper> tableChildQuery = null;
@ -815,7 +876,7 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
public String toSQL() {
String sql = DialectFactory.getDialect().forSelectByQuery(this);
return SqlUtil.replaceSqlParams(sql, getValueArray());
return SqlUtil.replaceSqlParams(sql, getAllValueArray());
}
@Override

View File

@ -58,7 +58,7 @@ public class SelectQueryColumn extends QueryColumn implements HasParamsColumn {
@Override
public Object[] getParamValues() {
return queryWrapper.getValueArray();
return queryWrapper.getAllValueArray();
}
}

View File

@ -42,7 +42,7 @@ public class SelectQueryTable extends QueryTable {
@Override
Object[] getValueArray() {
return queryWrapper.getValueArray();
return queryWrapper.getAllValueArray();
}
@Override

View File

@ -44,7 +44,7 @@ public class WithSelectDetail implements WithDetail {
@Override
public Object[] getParamValues() {
return queryWrapper.getValueArray();
return queryWrapper.getAllValueArray();
}
@Override

View File

@ -57,7 +57,7 @@ public class WithValuesDetail implements WithDetail {
@Override
public Object[] getParamValues() {
return queryWrapper.getValueArray();
return queryWrapper.getAllValueArray();
}
@Override

View File

@ -115,7 +115,7 @@ class WrapperUtil {
addParam(paras, Array.get(value, i));
}
} else if (value instanceof QueryWrapper) {
Object[] valueArray = ((QueryWrapper) value).getValueArray();
Object[] valueArray = ((QueryWrapper) value).getAllValueArray();
paras.addAll(Arrays.asList(valueArray));
} else if (value.getClass().isEnum()) {
EnumWrapper enumWrapper = EnumWrapper.of(value.getClass());

View File

@ -46,8 +46,6 @@ public interface IService<T> {
int DEFAULT_BATCH_SIZE = 1000;
// ===== 保存操作 =====
/**
* <p>获取对应实体类Entity的基础映射类BaseMapper
*
@ -55,27 +53,18 @@ public interface IService<T> {
*/
BaseMapper<T> getMapper();
// ===== 保存操作 =====
/**
* <p>保存实体类对象数据
*
* @param entity 实体类对象
* @return {@code true} 保存成功{@code false} 保存失败
* @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法忽略
* {@code null} 字段的数据使数据库配置的默认值生效
* @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法忽略实体类
* {@code null} 属性的数据使数据库配置的默认值生效
*/
default boolean save(T entity) {
return SqlUtil.toBool(getMapper().insertSelective(entity));
}
/**
* <p>保存或者更新实体类对象数据
*
* @param entity 实体类对象
* @return {@code true} 保存或更新成功{@code false} 保存或更新失败
* @apiNote 如果实体类对象主键有值则更新数据若没有值则保存数据
*/
default boolean saveOrUpdate(T entity) {
return SqlUtil.toBool(getMapper().insertOrUpdate(entity, true));
return SqlUtil.toBool(getMapper().insert(entity, true));
}
/**
@ -83,6 +72,8 @@ public interface IService<T> {
*
* @param entities 实体类对象
* @return {@code true} 保存成功{@code false} 保存失败
* @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法忽略实体类
* {@code null} 属性的数据使数据库配置的默认值生效
*/
default boolean saveBatch(Collection<T> entities) {
return saveBatch(entities, DEFAULT_BATCH_SIZE);
@ -94,10 +85,12 @@ public interface IService<T> {
* @param entities 实体类对象
* @param batchSize 每次保存切分的数量
* @return {@code true} 保存成功{@code false} 保存失败
* @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法忽略实体类
* {@code null} 属性的数据使数据库配置的默认值生效
*/
default boolean saveBatch(Collection<T> entities, int batchSize) {
Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::insert));
return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::insertSelective));
}
/**
@ -105,7 +98,10 @@ public interface IService<T> {
*
* @param entities 实体类对象
* @return {@code true} 保存成功{@code false} 保存失败
* @deprecated 为保持 Service API 一致性默认方法都是忽略实体类 {@code null} 属性的数据
* 另外该方法将在 1.6.0 版本被移除
*/
@Deprecated
default boolean saveBatchSelective(Collection<T> entities) {
return saveBatchSelective(entities, DEFAULT_BATCH_SIZE);
}
@ -116,12 +112,53 @@ public interface IService<T> {
* @param entities 实体类对象
* @param batchSize 每次保存切分的数量
* @return {@code true} 保存成功{@code false} 保存失败
* @deprecated 为保持 Service API 一致性默认方法都是忽略实体类 {@code null} 属性的数据
* 另外该方法将在 1.6.0 版本被移除
*/
@Deprecated
default boolean saveBatchSelective(Collection<T> entities, int batchSize) {
Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::insertSelective));
}
/**
* <p>保存或者更新实体类对象数据
*
* @param entity 实体类对象
* @return {@code true} 保存或更新成功{@code false} 保存或更新失败
* @apiNote 如果实体类对象主键有值则更新数据若没有值则保存数据无论新增还是更新都会忽略实体类
* {@code null} 属性的数据
*/
default boolean saveOrUpdate(T entity) {
return SqlUtil.toBool(getMapper().insertOrUpdate(entity, true));
}
/**
* <p>保存或者更新实体类对象数据
*
* @param entities 实体类对象
* @return {@code true} 保存或更新成功{@code false} 保存或更新失败
* @apiNote 如果实体类对象主键有值则更新数据若没有值则保存数据无论新增还是更新都会忽略实体类
* {@code null} 属性的数据
*/
default boolean saveOrUpdateBatch(Collection<T> entities) {
return saveOrUpdateBatch(entities, DEFAULT_BATCH_SIZE);
}
/**
* <p>保存或者更新实体类对象数据
*
* @param entities 实体类对象
* @param batchSize 每次操作切分的数量
* @return {@code true} 保存或更新成功{@code false} 保存或更新失败
* @apiNote 如果实体类对象主键有值则更新数据若没有值则保存数据无论新增还是更新都会忽略实体类
* {@code null} 属性的数据
*/
default boolean saveOrUpdateBatch(Collection<T> entities, int batchSize) {
Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::insertOrUpdateSelective));
}
// ===== 删除操作 =====
/**
@ -167,8 +204,6 @@ public interface IService<T> {
return SqlUtil.toBool(getMapper().deleteBatchByIds(ids));
}
// ===== 更新操作 =====
/**
* <p>根据 {@link Map} 构建查询条件删除数据
*
@ -183,6 +218,8 @@ public interface IService<T> {
return remove(query().where(query));
}
// ===== 更新操作 =====
/**
* <p>根据数据主键更新数据
*
@ -211,6 +248,7 @@ public interface IService<T> {
* @param entity 实体类对象
* @param query 查询条件
* @return {@code true} 更新成功{@code false} 更新失败
* @apiNote 若实体类属性数据为 {@code null}该属性不会新到数据库
*/
default boolean update(T entity, Map<String, Object> query) {
return update(entity, query().where(query));
@ -222,6 +260,7 @@ public interface IService<T> {
* @param entity 实体类对象
* @param query 查询条件
* @return {@code true} 更新成功{@code false} 更新失败
* @apiNote 若实体类属性数据为 {@code null}该属性不会新到数据库
*/
default boolean update(T entity, QueryWrapper query) {
return SqlUtil.toBool(getMapper().updateByQuery(entity, query));
@ -233,6 +272,7 @@ public interface IService<T> {
* @param entity 实体类对象
* @param condition 查询条件
* @return {@code true} 更新成功{@code false} 更新失败
* @apiNote 若实体类属性数据为 {@code null}该属性不会新到数据库
*/
default boolean update(T entity, QueryCondition condition) {
return update(entity, query().where(condition));
@ -243,6 +283,7 @@ public interface IService<T> {
*
* @param entities 实体类对象集合
* @return boolean {@code true} 更新成功{@code false} 更新失败
* @apiNote 若实体类属性数据为 {@code null}该属性不会新到数据库
*/
default boolean updateBatch(Collection<T> entities) {
return updateBatch(entities, DEFAULT_BATCH_SIZE);
@ -254,13 +295,13 @@ public interface IService<T> {
* @param entities 实体类对象集合
* @param batchSize 每批次更新数量
* @return {@code true} 更新成功{@code false} 更新失败
* @apiNote 若实体类属性数据为 {@code null}该属性不会新到数据库
*/
default boolean updateBatch(Collection<T> entities, int batchSize) {
Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::update));
}
// ===== 查询操作 =====
/**
@ -349,6 +390,70 @@ public interface IService<T> {
return Optional.ofNullable(getOne(condition));
}
/**
* <p>查询结果集中第一列且第一条数据
*
* @param query 查询条件
* @return 数据值
*/
default Object getObj(QueryWrapper query) {
return getMapper().selectObjectByQuery(query);
}
/**
* <p>查询结果集中第一列且第一条数据并封装为 {@link Optional} 返回
*
* @param query 查询条件
* @return 数据值
*/
default Optional<Object> getObjOpt(QueryWrapper query) {
return Optional.ofNullable(getObj(query));
}
/**
* <p>查询结果集中第一列且第一条数据并转换为指定类型比如 {@code Long}, {@code String}
*
* @param query 查询条件
* @param asType 接收的数据类型
* @return 数据值
*/
default <R> R getObjAs(QueryWrapper query, Class<R> asType) {
return getMapper().selectObjectByQueryAs(query, asType);
}
/**
* <p>查询结果集中第一列且第一条数据并转换为指定类型比如 {@code Long}, {@code String}
* 封装为 {@link Optional} 返回
*
* @param query 查询条件
* @param asType 接收的数据类型
* @return 数据值
*/
default <R> Optional<R> getObjAsOpt(QueryWrapper query, Class<R> asType) {
return Optional.ofNullable(getObjAs(query, asType));
}
/**
* <p>查询结果集中第一列所有数据
*
* @param query 查询条件
* @return 数据列表
*/
default List<Object> objList(QueryWrapper query) {
return getMapper().selectObjectListByQuery(query);
}
/**
* <p>查询结果集中第一列所有数据并转换为指定类型比如 {@code Long}, {@code String}
*
* @param query 查询条件
* @param asType 接收的数据类型
* @return 数据列表
*/
default <R> List<R> objListAs(QueryWrapper query, Class<R> asType) {
return getMapper().selectObjectListByQueryAs(query, asType);
}
/**
* <p>查询所有数据
*
@ -428,7 +533,7 @@ public interface IService<T> {
* @return {@code true} 数据存在{@code false} 数据不存在
*/
default boolean exists(QueryCondition condition) {
return CollectionUtil.isNotEmpty(getMapper().selectListByCondition(condition,1L));
return CollectionUtil.isNotEmpty(getMapper().selectListByCondition(condition, 1L));
}
/**

View File

@ -45,21 +45,6 @@ public class IdInfo extends ColumnInfo {
private Boolean before;
public IdInfo(ColumnInfo columnInfo) {
this.setColumn(columnInfo.getColumn());
this.setAlias(columnInfo.getAlias());
this.setProperty(columnInfo.getProperty());
this.setPropertyType(columnInfo.getPropertyType());
// id 的类型为数值时默认设置为自增的方式
if (Number.class.isAssignableFrom(columnInfo.getPropertyType())) {
keyType = KeyType.Auto;
} else {
initDefaultKeyType();
}
}
public IdInfo(Id id) {
this.keyType = id.keyType();
this.value = id.value();

View File

@ -376,7 +376,7 @@ public class TableInfo {
primaryColumns[i] = idInfo.getColumn();
if (idInfo.getKeyType() != KeyType.Auto
|| (idInfo.getBefore() != null && idInfo.getBefore())
&& (idInfo.getBefore() != null && idInfo.getBefore())
) {
insertIdFields.add(idInfo.getColumn());
}

View File

@ -17,7 +17,6 @@ package com.mybatisflex.core.table;
import com.mybatisflex.annotation.*;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.FlexConsts;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.util.ClassUtil;
@ -28,10 +27,7 @@ import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.apache.ibatis.type.UnknownTypeHandler;
import org.apache.ibatis.type.*;
import org.apache.ibatis.util.MapUtil;
import java.lang.reflect.*;
@ -179,7 +175,7 @@ public class TableInfoFactory {
List<ColumnInfo> columnInfoList = new ArrayList<>();
List<IdInfo> idInfos = new ArrayList<>();
Field idField = null;
// Field idField = null;
String logicDeleteColumn = null;
String versionColumn = null;
@ -200,6 +196,8 @@ public class TableInfoFactory {
List<Field> entityFields = getColumnFields(entityClass);
FlexGlobalConfig config = FlexGlobalConfig.getDefaultConfig();
for (Field field : entityFields) {
Column column = field.getAnnotation(Column.class);
@ -219,7 +217,7 @@ public class TableInfoFactory {
Type genericType = TypeParameterResolver.resolveFieldType(field, entityClass);
if (genericType instanceof ParameterizedType) {
Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (actualTypeArgument instanceof Class){
if (actualTypeArgument instanceof Class) {
tableInfo.addCollectionType(field, (Class<?>) actualTypeArgument);
}
}
@ -237,7 +235,8 @@ public class TableInfoFactory {
String columnName = getColumnName(tableInfo.isCamelToUnderline(), field, column);
//逻辑删除字段
if (column != null && column.isLogicDelete()) {
if ((column != null && column.isLogicDelete())
|| columnName.equals(config.getLogicDeleteColumn())) {
if (logicDeleteColumn == null) {
logicDeleteColumn = columnName;
} else {
@ -246,7 +245,8 @@ public class TableInfoFactory {
}
//乐观锁版本字段
if (column != null && column.version()) {
if ((column != null && column.version())
|| columnName.equals(config.getVersionColumn())) {
if (versionColumn == null) {
versionColumn = columnName;
} else {
@ -255,7 +255,8 @@ public class TableInfoFactory {
}
//租户ID 字段
if (column != null && column.tenantId()) {
if ((column != null && column.tenantId())
|| columnName.equals(config.getTenantColumn())) {
if (tenantIdColumn == null) {
tenantIdColumn = columnName;
} else {
@ -311,10 +312,22 @@ public class TableInfoFactory {
columnInfo.setPropertyType(fieldType);
if (column != null && column.typeHandler() != UnknownTypeHandler.class) {
Class<?> typeHandlerClass = column.typeHandler();
Configuration configuration = FlexGlobalConfig.getDefaultConfig().getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
TypeHandler<?> typeHandler = typeHandlerRegistry.getInstance(columnInfo.getPropertyType(), typeHandlerClass);
TypeHandler<?> typeHandler;
// 集合类型传入泛型
// fixed https://gitee.com/mybatis-flex/mybatis-flex/issues/I7S2YE
if (Collection.class.isAssignableFrom(fieldType)) {
typeHandler = createCollectionTypeHandler(entityClass, field, column.typeHandler(), fieldType);
}
//非集合类型
else {
Class<?> typeHandlerClass = column.typeHandler();
Configuration configuration = FlexGlobalConfig.getDefaultConfig().getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
typeHandler = typeHandlerRegistry.getInstance(columnInfo.getPropertyType(), typeHandlerClass);
}
columnInfo.setTypeHandler(typeHandler);
}
@ -330,27 +343,9 @@ public class TableInfoFactory {
columnInfo.setJdbcType(column.jdbcType());
}
if (FlexConsts.DEFAULT_PRIMARY_FIELD.equals(field.getName())) {
idField = field;
}
}
if (idInfos.isEmpty() && idField != null) {
int index = -1;
for (int i = 0; i < columnInfoList.size(); i++) {
ColumnInfo columnInfo = columnInfoList.get(i);
if (FlexConsts.DEFAULT_PRIMARY_FIELD.equals(columnInfo.getProperty())) {
index = i;
break;
}
}
if (index >= 0) {
ColumnInfo removedColumnInfo = columnInfoList.remove(index);
idInfos.add(new IdInfo(removedColumnInfo));
}
}
tableInfo.setLogicDeleteColumn(logicDeleteColumn);
tableInfo.setVersionColumn(versionColumn);
tableInfo.setTenantIdColumn(tenantIdColumn);
@ -378,6 +373,48 @@ public class TableInfoFactory {
return tableInfo;
}
/**
* 创建 typeHandler
* 参考 {@link TypeHandlerRegistry#getInstance(Class, Class)}
*
* @param entityClass
* @param field
* @param typeHandlerClass
* @param fieldType
*/
private static TypeHandler<?> createCollectionTypeHandler(Class<?> entityClass, Field field, Class<?> typeHandlerClass, Class<?> fieldType) {
Class<?> genericClass = null;
Type genericType = TypeParameterResolver.resolveFieldType(field, entityClass);
if (genericType instanceof ParameterizedType) {
Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (actualTypeArgument instanceof Class) {
genericClass = (Class<?>) actualTypeArgument;
}
}
try {
Constructor<?> constructor = typeHandlerClass.getConstructor(Class.class, Class.class);
return (TypeHandler<?>) constructor.newInstance(fieldType, genericClass);
} catch (NoSuchMethodException ignored) {
} catch (Exception e) {
throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
}
try {
Constructor<?> constructor = typeHandlerClass.getConstructor(Class.class);
return (TypeHandler<?>) constructor.newInstance(fieldType);
} catch (NoSuchMethodException ignored) {
} catch (Exception e) {
throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
}
try {
Constructor<?> c = typeHandlerClass.getConstructor();
return (TypeHandler<?>) c.newInstance();
} catch (Exception e) {
throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
}
}
static String getColumnName(boolean isCamelToUnderline, Field field, Column column) {
if (column != null && StringUtil.isNotBlank(column.value())) {
return column.value();

View File

@ -92,12 +92,12 @@ public class UpdateChain<T> extends QueryWrapperAdapter<UpdateChain<T>> {
return this;
}
public UpdateChain<T> set(LambdaGetter<T> getter, Object value, boolean condition) {
public <L> UpdateChain<T> set(LambdaGetter<L> getter, Object value, boolean condition) {
entityWrapper.set(getter, value, condition);
return this;
}
public UpdateChain<T> set(LambdaGetter<T> getter, Object value) {
public <L> UpdateChain<T> set(LambdaGetter<L> getter, Object value) {
entityWrapper.set(getter, value);
return this;
}
@ -123,12 +123,12 @@ public class UpdateChain<T> extends QueryWrapperAdapter<UpdateChain<T>> {
return this;
}
public UpdateChain<T> setRaw(LambdaGetter<T> getter, Object value, boolean condition) {
public <L> UpdateChain<T> setRaw(LambdaGetter<L> getter, Object value, boolean condition) {
entityWrapper.setRaw(getter, value, condition);
return this;
}
public UpdateChain<T> setRaw(LambdaGetter<T> getter, Object value) {
public <L> UpdateChain<T> setRaw(LambdaGetter<L> getter, Object value) {
entityWrapper.setRaw(getter, value);
return this;
}

View File

@ -44,7 +44,7 @@ public class LambdaUtil {
public static <T> Class<?> getImplClass(LambdaGetter<T> getter) {
SerializedLambda lambda = getSerializedLambda(getter);
return getImplClass(lambda);
return getImplClass(lambda, getter.getClass().getClassLoader());
}
@ -56,9 +56,10 @@ public class LambdaUtil {
public static <T> QueryColumn getQueryColumn(LambdaGetter<T> getter) {
ClassLoader classLoader = getter.getClass().getClassLoader();
SerializedLambda lambda = getSerializedLambda(getter);
String methodName = lambda.getImplMethodName();
Class<?> entityClass = getImplClass(lambda);
Class<?> entityClass = getImplClass(lambda, classLoader);
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
return tableInfo.getQueryColumnByProperty(PropertyNamer.methodToProperty(methodName));
}
@ -77,11 +78,11 @@ public class LambdaUtil {
}
private static Class<?> getImplClass(SerializedLambda lambda) {
private static Class<?> getImplClass(SerializedLambda lambda, ClassLoader classLoader) {
String implClass = getImplClassName(lambda);
return MapUtil.computeIfAbsent(classMap, implClass, s -> {
try {
return Class.forName(s.replace("/", "."));
return Class.forName(s.replace("/", "."), true, classLoader);
} catch (ClassNotFoundException e) {
throw FlexExceptions.wrap(e);
}

View File

@ -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);
}

View File

@ -359,6 +359,21 @@ public class AccountSqlTester {
System.out.println(sql);
}
@Test
public void testJoin4Sql() {
QueryWrapper query = QueryWrapper.create()
.select(ACCOUNT.ALL_COLUMNS,
column("bui.user_code"),
column("bui.user_name"),
column("burmc.user_name as created_by_name"))
.from(ACCOUNT).as("burm")
.leftJoin("base_admin_user_info").as("bui").on("bui.user_id = burm.user_id")
.leftJoin("base_admin_user_info").as("burmc").on("burmc.user_id = burm.created_by")
.where("bui.is_valid = ?", 3);
System.out.println(query.toSQL());
}
@Test
public void testJoinSelf() {
QueryWrapper queryWrapper = QueryWrapper.create()

View File

@ -0,0 +1,82 @@
/*
* 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.coretest;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.CollectionUtil;
import com.mybatisflex.core.util.StringUtil;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static com.mybatisflex.coretest.table.AccountTableDef.ACCOUNT;
/**
* 动态条件测试
*
* @author 王帅
* @since 2023-08-10
*/
public class DynamicConditionTest {
@Test
public void test01() {
String sql = QueryWrapper.create()
.from(ACCOUNT)
.where(ACCOUNT.AGE.ge(18))
.or(qw -> qw.where(ACCOUNT.ID.eq(1)), false)
.toSQL();
System.out.println(sql);
}
@Test
public void test02() {
List<Integer> idList = Arrays.asList(1, 2, 3);
String sql = QueryWrapper.create()
.from(ACCOUNT)
.where(ACCOUNT.ID.in(idList).when(false))
.where(ACCOUNT.ID.in(idList, CollectionUtil::isNotEmpty))
.where(ACCOUNT.ID.in(idList).when(idList::isEmpty))
.toSQL();
System.out.println(sql);
}
@Test
public void test03() {
String sql = QueryWrapper.create()
.from(ACCOUNT)
.where(ACCOUNT.ID.eq("1", StringUtil::isNumeric))
.toSQL();
System.out.println(sql);
}
@Test
public void test04() {
String sql = QueryWrapper.create()
.from(ACCOUNT)
.where(ACCOUNT.ID.between('1', '2', (start, end) -> start < end))
.toSQL();
System.out.println(sql);
}
}

View File

@ -52,4 +52,27 @@ public class FunctionSqlTest {
System.out.println(sql);
}
@Test
public void test03() {
String sql = QueryWrapper.create()
.select()
.from(ACCOUNT)
.where(upper(ACCOUNT.USER_NAME).likeRaw(raw("UPPER('ws')")))
.toSQL();
System.out.println(sql);
}
@Test
public void test04() {
String sql = QueryWrapper.create()
.select()
.from(ACCOUNT)
// .where("FIND_IN_SET(?, `id`)", 100)
.where(findInSet(number(100), ACCOUNT.ID).eq(true))
.toSQL();
System.out.println(sql);
}
}

72
mybatis-flex-kotlin/pom.xml Executable file
View File

@ -0,0 +1,72 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mybatis-flex</groupId>
<artifactId>parent</artifactId>
<version>1.5.7</version>
</parent>
<artifactId>mybatis-flex-kotlin</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.version>1.9.0</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-core</artifactId>
<version>${mybatis-flex.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<args>
<arg>-Xjvm-default=all</arg>
</args>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,55 @@
/*
* 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.kotlin.db
import java.util.NoSuchElementException
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* 数据库配置对象暂时未启用
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
object DbConfig {
var url: String by IfNullVar { "" }
var username: String by IfNullVar { "" }
var password: String by IfNullVar { "" }
}
class IfNullVar<T : Any>(private var init: (() -> T)?) : ReadWriteProperty<Any?, T> {
private var _value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (_value == null && init != null) {
synchronized(this) {
if (_value == null) {
_value = init?.invoke()
//释放引用
init = null
}
}
}
return this._value?:throw NoSuchElementException()
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
_value = value
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.kotlin.entry
import com.mybatisflex.core.dialect.DialectFactory
import com.mybatisflex.core.row.Db.*
import com.mybatisflex.core.table.TableInfoFactory
import com.mybatisflex.core.util.ArrayUtil
import java.io.Serializable
/**
* 实体类父类继承该类后将赋予实体简单增删改操作
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
open class Entry :Serializable{
fun save(ignoreNulls: Boolean = true): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(this.javaClass)
//设置乐观锁版本字段的初始化数据
tableInfo.initVersionValueIfNecessary(this)
//设置租户ID
tableInfo.initTenantIdIfNecessary(this)
//设置逻辑删除字段的出初始化数据
tableInfo.initLogicDeleteValueIfNecessary(this)
//执行 onInsert 监听器
tableInfo.invokeOnInsertListener(this)
val values = tableInfo.buildInsertSqlArgs(this, ignoreNulls)
val sql = DialectFactory.getDialect().forInsertEntity(tableInfo, this, ignoreNulls)
return insertBySql(sql, *values) == 1
}
fun update(ignoreNulls: Boolean = true): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(this.javaClass)
//执行 onUpdate 监听器
tableInfo.invokeOnUpdateListener(this)
val updateValues = tableInfo.buildUpdateSqlArgs(this, ignoreNulls, false)
val primaryValues = tableInfo.buildPkSqlArgs(this)
val tenantIdArgs = tableInfo.buildTenantIdArgs()
val sql = DialectFactory.getDialect().forUpdateEntity(tableInfo, this, ignoreNulls)
return updateBySql(sql, *ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs)) == 1
}
fun deleteById(): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(this.javaClass)
val primaryValues = tableInfo.buildPkSqlArgs(this)
val allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs())
val sql = DialectFactory.getDialect().forDeleteEntityById(tableInfo)
return deleteBySql(sql, *allValues) == 1
}
}

View File

@ -0,0 +1,116 @@
/*
* 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.kotlin.extensions.db
import com.mybatisflex.core.BaseMapper
import com.mybatisflex.core.MybatisFlexBootstrap
import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.row.Db.selectListByQuery
import com.mybatisflex.core.row.Db.selectOneByQuery
import com.mybatisflex.core.row.Row
import com.mybatisflex.core.table.TableDef
import com.mybatisflex.core.table.TableInfoFactory
import com.mybatisflex.kotlin.extensions.entry.filter
import com.mybatisflex.kotlin.extensions.entry.toEntities
import com.mybatisflex.kotlin.scope.QueryScope
import com.mybatisflex.kotlin.scope.queryScope
/**
* 数据库简单操作扩展
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
inline fun <reified M : BaseMapper<*>> mapper(): M = MybatisFlexBootstrap.getInstance().getMapper(M::class.java)
inline fun <reified T : Any> queryOne(
vararg columns: QueryColumn,
schema: String? = null,
tableName: String? = null,
noinline init: QueryScope.() -> Unit
): T = queryRow(schema = schema, tableName = tableName, columns = columns, init = init).toEntity(T::class.java)
fun queryRow(
vararg columns: QueryColumn?,
schema: String? = null,
tableName: String? = null,
init: QueryScope.() -> Unit
): Row =
selectOneByQuery(
schema,
tableName,
queryScope(columns = columns, init = init)
)
inline fun <reified T> query(
vararg columns: QueryColumn?,
schema: String? = null,
tableName: String? = null,
noinline init: QueryScope.() -> Unit
): List<T> =
queryRows(schema = schema, tableName = tableName, columns = columns, init = init)
.toEntities()
fun queryRows(
vararg columns: QueryColumn?,
schema: String? = null,
tableName: String? = null,
init: QueryScope.() -> Unit
): List<Row> = selectListByQuery(
schema,tableName,queryScope(columns = columns, init = init)
)
// filter-----------
inline fun <reified E> filter(
tableName: String,
schema: String,
vararg columns: QueryColumn?,
queryCondition: QueryCondition = QueryCondition.createEmpty()
): List<E> = selectListByQuery(
schema,
tableName,
queryScope(*columns).where(queryCondition)
).toEntities()
inline fun <reified E> filter(
vararg columns: QueryColumn?,
init: () -> QueryCondition
): List<E> {
val tableInfo = TableInfoFactory.ofEntityClass(E::class.java)
return filter<E>(
columns = columns,
schema = tableInfo.schema,
tableName = tableInfo.tableName,
queryCondition = init()
)
}
inline fun <reified E, T : TableDef> filter(
tableDef: T,
vararg columns: QueryColumn?,
init: T.() -> QueryCondition
): List<E> = tableDef.filter(columns = columns, init = init)

View File

@ -0,0 +1,99 @@
/*
* 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.kotlin.extensions.entry
import com.mybatisflex.core.FlexConsts
import com.mybatisflex.core.dialect.DialectFactory
import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.row.Db.*
import com.mybatisflex.kotlin.extensions.db.*
import com.mybatisflex.core.row.Row
import com.mybatisflex.core.row.RowUtil
import com.mybatisflex.core.table.TableDef
import com.mybatisflex.core.table.TableInfoFactory
import com.mybatisflex.core.util.ArrayUtil
import com.mybatisflex.kotlin.entry.Entry
import com.mybatisflex.kotlin.scope.QueryScope
import java.util.Arrays
/*
* 实体操作扩展
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
infix fun <T> Row.to(entryClass: Class<T>): T {
return RowUtil.toEntity(this, entryClass)
}
inline fun <reified E, T : TableDef> T.filter(
vararg columns: QueryColumn?,
init: T.() -> QueryCondition
): List<E> {
val tableInfo = TableInfoFactory.ofEntityClass(E::class.java)
return filter<E>(
columns = columns,
schema = tableInfo.schema,
tableName = tableInfo.tableName,
queryCondition = init()
)
}
inline fun <reified E> TableDef.query(
vararg columns: QueryColumn?,
noinline init: QueryScope.() -> Unit
): List<E> {
return query<E>(
columns = columns,
schema = this.schema,
tableName = this.tableName,
init = init
)
}
inline fun <reified E> TableDef.all(): List<E> = selectAll(schema, tableName).toEntities()
inline fun <reified E> Collection<Row>.toEntities() = map { it to E::class.java }.toList()
inline fun<reified E:Entry> List<E>.batchInsert(): Boolean {
val entities = this
val tableInfo = TableInfoFactory.ofEntityClass(E::class.java)
for (entity in entities) {
tableInfo.initVersionValueIfNecessary(entity)
tableInfo.initTenantIdIfNecessary(entity)
tableInfo.initLogicDeleteValueIfNecessary(entity)
//执行 onInsert 监听器
tableInfo.invokeOnInsertListener(entity)
}
var allValues = FlexConsts.EMPTY_ARRAY
for (entity in entities) {
allValues = ArrayUtil.concat(allValues, tableInfo.buildInsertSqlArgs(entity, false))
}
val sql = DialectFactory.getDialect().forInsertEntityBatch(tableInfo, entities)
return insertBySql(sql,*allValues) > 1
}
fun< E:Entry> List<E>.batchUpdate(): Boolean = all(Entry::update)
inline fun<reified E:Entry> List<E>. batchDeleteById(): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(E::class.java)
val primaryValues = this.map { tableInfo.buildPkSqlArgs(it) }.stream().flatMap(Arrays::stream).toArray()
val tenantIdArgs = tableInfo.buildTenantIdArgs()
val sql = DialectFactory.getDialect().forDeleteEntityBatchByIds(tableInfo, primaryValues)
return deleteBySql(sql,*ArrayUtil.concat(primaryValues, tenantIdArgs)) > 1
}

View File

@ -0,0 +1,37 @@
/*
* 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.kotlin.extensions.mapper
import com.mybatisflex.core.BaseMapper
import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.kotlin.scope.QueryScope
import com.mybatisflex.kotlin.scope.queryScope
/*
* 映射器操作扩展
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
fun <T> BaseMapper<*>.queryList(init: (QueryScope.() -> Unit)? = null): List<T> =
this.selectListByQuery(queryScope(init = init)) as List<T>
fun <T> BaseMapper<T>.update(entity: T, init: () -> QueryCondition): Int =
this.updateByCondition(entity, init())
fun <T> BaseMapper<T>.delete(init: (QueryScope.() -> Unit)? = null): Int =
this.deleteByQuery(queryScope(init = init))
fun <T> BaseMapper<T>.delete1(init: () -> QueryCondition): Int =
this.deleteByCondition(init())

View File

@ -0,0 +1,74 @@
/*
* 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.kotlin.extensions.sql
import com.mybatisflex.core.query.Joiner
import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.query.QueryWrapper
import java.util.function.Consumer
/*
* sql操作扩展
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
infix fun QueryColumn.eq(value: Any?): QueryCondition {
return this.eq(value)
}
inline fun QueryCondition.andIf(test: Boolean, block: () -> QueryCondition): QueryCondition {
if (test) {
this.and(block())
}
return this
}
inline fun QueryCondition.orIf(test: Boolean, block: () -> QueryCondition): QueryCondition {
if (test) {
this.or(block())
}
return this
}
inline fun `if`(test: Boolean, block: () -> QueryCondition): QueryCondition {
if (test) {
return block()
}
return QueryCondition.createEmpty()
}
infix fun QueryColumn.like(value: String): QueryCondition = this.like(value)
infix fun QueryCondition.and(other: QueryCondition): QueryCondition = this.and(other)
infix fun QueryCondition.or(other: QueryCondition): QueryCondition = this.or(other)
infix fun QueryColumn.`=`(value: Any?): QueryCondition = this.eq(value)
infix fun QueryColumn.`in`(value: Collection<Any>): QueryCondition = this.`in`(value)
fun QueryColumn.`in`(vararg values: Array<Any>): QueryCondition = this.`in`(values.asList())
infix fun QueryWrapper.`as`(alias: String) = this.`as`(alias)
infix fun <M> Joiner<M>.`as`(alias: String?): Joiner<M> = this.`as`(alias)
infix fun <M> Joiner<M>.on(on: String?): M = this.on(on)
infix fun <M> Joiner<M>.on(on: QueryCondition?): M = this.on(on)
infix fun <M> Joiner<M>.on(consumer: Consumer<QueryWrapper?>): M = this.on(consumer)

View File

@ -0,0 +1,61 @@
package com.mybatisflex.kotlin.scope
/*
* 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.
*/
import com.mybatisflex.core.MybatisFlexBootstrap
import javax.sql.DataSource
class BootstrapScope(private val instant: MybatisFlexBootstrap = MybatisFlexBootstrap.getInstance()) {
fun dataSources(dataSourceScope: DataSourceScope.() -> Unit) =
dataSourceScope(DataSourceScope(instant))
operator fun <T> Class<T>.unaryPlus(): MybatisFlexBootstrap =
instant.addMapper(this)
operator fun DataSource.unaryPlus(): MybatisFlexBootstrap =
instant.setDataSource(this)
infix fun String.of(dataSource: DataSource): MybatisFlexBootstrap =
instant.setDataSource(this, dataSource)
}
class DataSourceScope(private val bootstrap: MybatisFlexBootstrap) {
fun dataSource(dataSourceKey: String, dataSource: DataSource) =
bootstrap.addDataSource(dataSourceKey, dataSource)
// infix fun String.of(dataSource: DataSource) =
// bootstrap.addDataSource(this, dataSource)
}
fun buildBootstrap(
instant: MybatisFlexBootstrap = MybatisFlexBootstrap.getInstance(),
scope: BootstrapScope.(MybatisFlexBootstrap) -> Unit
): MybatisFlexBootstrap {
scope(BootstrapScope(instant), instant)
return instant
}

View File

@ -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.kotlin.scope
import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.query.QueryWrapper
import com.mybatisflex.core.table.TableDef
/**
* 查询作用域
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
class QueryScope :QueryWrapper() {
companion object CurrentQueryScope : ThreadLocal<QueryScope>()
fun from(init: (QueryScope.() -> Unit)? = null): QueryWrapper = this.from(queryScope(init = init))
fun <T : TableDef> where(tableDef: T, build: T.() -> QueryCondition): QueryWrapper = this.where(build(tableDef))
fun where(build: QueryScope.() -> QueryCondition): QueryWrapper = this.where(build(this))
operator fun String.get(name: String): QueryColumn = QueryColumn(this, name)
operator fun String.unaryMinus(): QueryColumn = QueryColumn(this)
}
fun queryScope(vararg columns: QueryColumn?, init: (QueryScope.() -> Unit)? = null): QueryWrapper {
val builder = QueryScope()
if (columns.isNotEmpty()) {
builder.select(*columns)
}
//用于嵌套查询拿到上层查询包装对象
init?.also {
val prentQueryScope = QueryScope.get()
QueryScope.set(builder)
it(builder)
QueryScope.set(prentQueryScope)
}
return builder
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -95,6 +95,7 @@
<groupId>io.seata</groupId>
<artifactId>seata-rm-datasource</artifactId>
<version>1.7.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@ -86,7 +86,7 @@ public class MultiDataSourceAutoConfiguration {
DataSourceManager.decryptDataSource(dataSource);
if (seataConfig != null && seataConfig.isEnable()) {
if (seataConfig.getSeataMode() == SeataMode.XA) {
if (seataConfig.getSeataMode() == MybatisFlexProperties.SeataMode.XA) {
dataSource = new DataSourceProxyXA(dataSource);
} else {
dataSource = new DataSourceProxy(dataSource);

View File

@ -41,6 +41,7 @@ import java.util.stream.Stream;
/**
* Mybatis-Flex 的配置属性
* 参考https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MybatisProperties.java
*
* @author Eddú Meléndez
* @author Kazuki Shimizu
* @author micahel
@ -777,22 +778,36 @@ public class MybatisFlexProperties {
private Object normalValueOfLogicDelete = FlexConsts.LOGIC_DELETE_NORMAL;
/**
* 逻辑删除数据删除标记值
* 逻辑删除数据删除标记值
*/
private Object deletedValueOfLogicDelete = FlexConsts.LOGIC_DELETE_DELETED;
/**
* 默认的分页查询时的每页数据量
* 默认的分页查询时的每页数据量
*/
private int defaultPageSize = 10;
/**
* 默认的 Relation 注解查询深度
* 默认的 Relation 注解查询深度
*/
private int defaultRelationQueryDepth = 2;
/**
* 默认的逻辑删除字段
*/
private String logicDeleteColumn = "del_flag";
/**
* 默认的多租户字段
*/
private String tenantColumn = "tenant_id";
/**
* 默认的乐观锁字段
*/
private String versionColumn = "version";
public boolean isPrintBanner() {
return printBanner;
@ -842,6 +857,30 @@ public class MybatisFlexProperties {
this.defaultRelationQueryDepth = defaultRelationQueryDepth;
}
public String getLogicDeleteColumn() {
return logicDeleteColumn;
}
public void setLogicDeleteColumn(String logicDeleteColumn) {
this.logicDeleteColumn = logicDeleteColumn;
}
public String getTenantColumn() {
return tenantColumn;
}
public void setTenantColumn(String tenantColumn) {
this.tenantColumn = tenantColumn;
}
public String getVersionColumn() {
return versionColumn;
}
public void setVersionColumn(String versionColumn) {
this.versionColumn = versionColumn;
}
void applyTo(FlexGlobalConfig target) {
PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
mapper.from(isPrintBanner()).to(target::setPrintBanner);
@ -850,6 +889,9 @@ public class MybatisFlexProperties {
mapper.from(getDeletedValueOfLogicDelete()).to(target::setDeletedValueOfLogicDelete);
mapper.from(getDefaultPageSize()).to(target::setDefaultPageSize);
mapper.from(getDefaultRelationQueryDepth()).to(target::setDefaultRelationQueryDepth);
mapper.from(getLogicDeleteColumn()).to(target::setLogicDeleteColumn);
mapper.from(getVersionColumn()).to(target::setVersionColumn);
mapper.from(getTenantColumn()).to(target::setTenantColumn);
}
}
@ -908,7 +950,7 @@ public class MybatisFlexProperties {
*
* @author life
*/
public static class SeataConfig{
public static class SeataConfig {
/**
* 是否开启
@ -935,6 +977,18 @@ public class MybatisFlexProperties {
public void setSeataMode(SeataMode seataMode) {
this.seataMode = seataMode;
}
}
/**
* @author life
*/
public enum SeataMode {
XA,
AT
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -39,8 +39,6 @@
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -88,6 +88,6 @@ public class FlexSpringTransaction implements Transaction {
@Override
public Integer getTimeout() throws SQLException {
return getConnection().getNetworkTimeout();
return null;
}
}

View File

@ -35,7 +35,6 @@ import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.type.TypeHandler;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>mybatis-flex-test</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -49,7 +49,7 @@ public class Account extends BaseEntity implements Serializable, AgeAware {
@Column(typeHandler = Fastjson2TypeHandler.class)
private Map<String, Object> options;
@Column(isLogicDelete = true)
// @Column(isLogicDelete = true)
private Boolean isDelete;
private List<Article> articles;

View File

@ -15,6 +15,7 @@
*/
package com.mybatisflex.test;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.MybatisFlexBootstrap;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
@ -23,6 +24,7 @@ import com.mybatisflex.core.mybatis.Mappers;
import com.mybatisflex.core.query.If;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.core.update.UpdateWrapper;
import com.mybatisflex.core.util.UpdateEntity;
import com.mybatisflex.mapper.ArticleMapper;
@ -52,6 +54,9 @@ public class AccountTester {
.addScript("data.sql")
.build();
FlexGlobalConfig.getDefaultConfig()
.setLogicDeleteColumn("is_delete");
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
.setDataSource(dataSource)
.setLogImpl(StdOutImpl.class)
@ -71,6 +76,11 @@ public class AccountTester {
articleMapper = bootstrap.getMapper(ArticleMapper.class);
}
@Test
public void testLogicDelete() {
accountMapper.selectAll().forEach(System.out::println);
}
@Test
public void testExecutor() {
DbChain.create()
@ -139,7 +149,7 @@ public class AccountTester {
@Test
public void testUpdate() {
public void testUpdate1() {
List<Account> accounts = accountMapper.selectAll();
System.out.println(accounts);
@ -154,7 +164,25 @@ public class AccountTester {
accounts = accountMapper.selectAll();
System.out.println(accounts);
}
@Test
public void testUpdate2() {
List<Account> accounts = accountMapper.selectAll();
System.out.println(accounts);
UpdateChain.of(Account.class)
.set(Account::getUserName,"zhangsan123")
// .leftJoin(ARTICLE).on(ARTICLE.ACCOUNT_ID.eq(ACCOUNT.ID))
.where(Account::getId).eq(1)
// .and(ARTICLE.ID.ge(0))
.limit(1)
.remove();
accounts = accountMapper.selectAll();
System.out.println(accounts);
}
/**

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.test;
import com.mybatisflex.core.MybatisFlexBootstrap;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
import com.mybatisflex.core.audit.MessageCollector;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.mapper.ArticleMapper;
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author 王帅
* @since 2023-08-10
*/
public class ArticleTester {
static ArticleMapper articleMapper;
@BeforeClass
public static void init() {
DataSource dataSource = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("schema.sql")
.addScript("data.sql")
.build();
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
.setDataSource(dataSource)
.setLogImpl(NoLoggingImpl.class)
.addMapper(ArticleMapper.class)
.start();
//开启审计功能
AuditManager.setAuditEnable(true);
//设置 SQL 审计收集器
MessageCollector collector = new ConsoleMessageCollector();
AuditManager.setMessageCollector(collector);
articleMapper = bootstrap.getMapper(ArticleMapper.class);
}
@Test
public void testBatch() {
int count = 10;
Collection<Article> articles = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
Article article = new Article();
article.setTitle("title" + i);
articles.add(article);
}
Db.executeBatch(articles, ArticleMapper.class, ArticleMapper::insertOrUpdateSelective);
articleMapper.selectAll().forEach(System.out::println);
}
}

View File

@ -0,0 +1,78 @@
/*
* 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;
import com.mybatisflex.core.util.ClassUtil;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class LambdaTester {
static Function<Account, List<Article>> getArticles = Account::getArticles;
static BiConsumer<Account, List<Article>> setArticles = Account::setArticles;
static Map<String,Function<?,?>> getters = new HashMap<>();
{
getters.put("getArticles",getArticles);
}
static Map<String,BiConsumer<?,?>> setters = new HashMap<>();
{
setters.put("setArticles",setArticles);
}
public static void main(String[] args) throws Exception {
LambdaTester a = new LambdaTester();
// Function getArticles = JavaTester.getArticles;
Function getArticles =getters.get("getArticles");
Account account = new Account();
Method method = ClassUtil.getFirstMethod(Account.class, method1 -> "getArticles".equals(method1.getName()));
method.invoke(account);
List<Article> apply = ( List<Article>)getArticles.apply(account);
long timeMillis = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
List<Article> apply1 = (List<Article>) method.invoke(account);
}
System.out.println(">>>>> invoke: " +(System.currentTimeMillis() - timeMillis));
timeMillis = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
List<Article> apply2 = ( List<Article>)getArticles.apply(account);
}
System.out.println(">>>>> apply: " +(System.currentTimeMillis() - timeMillis));
}
// public static interface FlexFunction<T,R>{
// R apply(T t);
// }
}

View File

@ -16,7 +16,10 @@
package com.mybatisflex.test;
import com.mybatisflex.annotation.*;
import com.mybatisflex.annotation.ColumnMask;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.mask.Masks;
import java.util.Date;
@ -34,7 +37,7 @@ public class TenantAccount {
private Date birthday;
@Column(tenantId = true)
// @Column(tenantId = true)
private Long tenantId;
public Long getId() {

View File

@ -18,8 +18,6 @@ package com.mybatisflex.test;
import com.mybatisflex.core.MybatisFlexBootstrap;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.tenant.TenantFactory;
import com.mybatisflex.core.tenant.TenantManager;
import com.mybatisflex.mapper.TenantAccountMapper;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
@ -27,10 +25,6 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import static com.mybatisflex.core.query.QueryMethods.select;
import static com.mybatisflex.test.table.AccountTableDef.ACCOUNT;
import static com.mybatisflex.test.table.TenantAccountTableDef.TENANT_ACCOUNT;
public class TenantTester {
public static void main(String[] args) {
@ -52,24 +46,22 @@ public class TenantTester {
AuditManager.setMessageCollector(new ConsoleMessageCollector());
//配置 tenantFactory
TenantManager.setTenantFactory(new TenantFactory() {
@Override
public Object[] getTenantIds() {
return new Object[]{1, 2};
}
});
TenantManager.setTenantFactory(() -> new Object[]{1, 2});
TenantAccountMapper mapper = MybatisFlexBootstrap.getInstance().getMapper(TenantAccountMapper.class);
TenantAccountMapper mapper = MybatisFlexBootstrap.getInstance()
.getMapper(TenantAccountMapper.class);
mapper.selectListByQuery(QueryWrapper.create()
.select(TENANT_ACCOUNT.ALL_COLUMNS)
.from(TENANT_ACCOUNT.as("c"), ACCOUNT.as("b"))
.where(TENANT_ACCOUNT.ID.eq(ACCOUNT.ID))
.and(TENANT_ACCOUNT.ID.eq(1))
.unionAll(select(TENANT_ACCOUNT.ALL_COLUMNS).from(TENANT_ACCOUNT)
.where(TENANT_ACCOUNT.ID.eq(2))
)
);
mapper.selectAll().forEach(System.out::println);
// mapper.selectListByQuery(QueryWrapper.create()
// .select(TENANT_ACCOUNT.ALL_COLUMNS)
// .from(TENANT_ACCOUNT.as("c"), ACCOUNT.as("b"))
// .where(TENANT_ACCOUNT.ID.eq(ACCOUNT.ID))
// .and(TENANT_ACCOUNT.ID.eq(1))
// .unionAll(select(TENANT_ACCOUNT.ALL_COLUMNS).from(TENANT_ACCOUNT)
// .where(TENANT_ACCOUNT.ID.eq(2))
// )
// );
// mapper.deleteBatchByIds(Arrays.asList(1, 2));

View File

@ -1,3 +1,19 @@
/*
* 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;
import com.mybatisflex.core.MybatisFlexBootstrap;
@ -15,6 +31,7 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import static com.mybatisflex.test.table.AccountTableDef.ACCOUNT;
import static com.mybatisflex.test.table.ArticleTableDef.ARTICLE;
public class UpdateChainTest {
@ -69,4 +86,17 @@ public class UpdateChainTest {
.list()
.forEach(System.out::println);
}
@Test
public void testUpdateChainToSql() {
String sql = UpdateChain.of(Account.class)
.set(ACCOUNT.AGE, 18)
.set(Article::getAccountId, 4, 1 == 1)
.leftJoin(ARTICLE).on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
.where(ACCOUNT.ID.eq(4))
.toSQL();
System.out.println(sql);
}
}

View File

@ -4,5 +4,5 @@ CREATE TABLE IF NOT EXISTS `tb_account`
`user_name` VARCHAR(100),
`age` INTEGER,
`birthday` DATETIME,
`tenant_id` INTEGER(11)
);
`tenant_id` INTEGER
);

View File

@ -0,0 +1 @@
processor.mapper.generateEnable=true

View File

@ -0,0 +1,67 @@
<?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">
<parent>
<artifactId>mybatis-flex-test</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-flex-seata-test</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</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-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,31 @@
/*
* 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;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.mybatisflex.test.mapper")
public class MybatisFlexSpringBootSeataApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisFlexSpringBootSeataApplication.class, args);
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.controller;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
import com.mybatisflex.core.audit.MessageCollector;
import com.mybatisflex.test.service.TestService;
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);
return String.valueOf(testService.buy());
}
}

View File

@ -1,13 +1,26 @@
package com.mybatisfle.test.mybatisflexspringbootseata.entity;
/*
* 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.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;
/**
* 实体类

View File

@ -1,13 +1,26 @@
package com.mybatisfle.test.mybatisflexspringbootseata.entity;
/*
* 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.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;
/**
* 实体类

View File

@ -1,13 +1,26 @@
package com.mybatisfle.test.mybatisflexspringbootseata.entity;
/*
* 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.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;
/**
* 实体类

View File

@ -1,23 +1,37 @@
package com.mybatisfle.test.mybatisflexspringbootseata.service;
/*
* 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.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 com.mybatisflex.test.entity.AccountTbl;
import com.mybatisflex.test.entity.OrderTbl;
import com.mybatisflex.test.entity.StockTbl;
import com.mybatisflex.test.entity.table.AccountTblTableDef;
import com.mybatisflex.test.mapper.AccountTblMapper;
import com.mybatisflex.test.mapper.OrderTblMapper;
import com.mybatisflex.test.mapper.StockTblMapper;
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 {
@ -33,12 +47,12 @@ public class TestService {
@Autowired
StockTblMapper stockTblMapper;
// @Transactional
// @Transactional
@GlobalTransactional
public boolean buy() {
// DataSourceKey.use("accountdb");
LOGGER.warn(() -> "xid:"+RootContext.getXID());
QueryWrapper account =new QueryWrapper();
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);
@ -59,4 +73,5 @@ public class TestService {
orderTblMapper.insert(orderTbl);
return true;
}
}

View File

@ -13,14 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.spring.boot;
/**
* @author life
*/
public enum SeataMode {
package com.mybatisflex.test;
XA,
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MybatisFlexSpringBootSeataApplicationTests {
@Test
void contextLoads() {
}
AT
}

View File

@ -1,155 +0,0 @@
<?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>1.5.6</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>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.0</version>
</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>

View File

@ -1,15 +0,0 @@
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);
}
}

View File

@ -1,28 +0,0 @@
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;
}
}

View File

@ -1,15 +0,0 @@
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> {
}

View File

@ -1,15 +0,0 @@
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> {
}

View File

@ -1,15 +0,0 @@
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> {
}

View File

@ -1,88 +0,0 @@
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;
}
}

View File

@ -1,13 +0,0 @@
package com.mybatisfle.test.mybatisflexspringbootseata;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MybatisFlexSpringBootSeataApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>mybatis-flex-test</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.5.6</version>
<version>1.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Some files were not shown because too many files have changed in this diff Show More