# toolkit-clean
**Repository Path**: glin/toolkit-clean
## Basic Information
- **Project Name**: toolkit-clean
- **Description**: MyBatis开发增强;是MyBatis-Plus的替换方案
为什么会有这样一个框架?
MyBatis-Plus的不足:1. 庞杂的类封装模式 2. selectone limit 1的问题 3. dao层对程序架构的侵入,破坏了整个架构风格的完整性 4. dao层对entity的依赖绑定
5. 分库分表的不足 6. Service层名称与实际作用的不匹配,引发整个项目命名错误的问题
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-05-20
- **Last Updated**: 2025-07-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 0️⃣ 简介
这是一个mybatis的增强工具,是MyBatis-Plus的替换方案
## 一、用法
1. 需要被加强的DAO层(MyBatis Mapper 接口),必须使用@Mapper(org.apache.ibatis.annotations.Mapper)注解标识
2. 需要被加强的DAO层(MyBatis Mapper 接口),必须继承CrudMapper(pub.cleangao.mybatis.dao.CrudMapper)
3. 需要扫描的Entity必须使用@Table注解(pub.cleangao.mybatis.annotation.Table)标识(必要时使用@Database注解)
4. 需要在应用项目的resources目录创建mybatis-enhance.properties文件;(或任何可加载资源的目录中)
*文件内容如下:*
```
## 实体类扫描路径
module.orm.entity-package = com.example.demo.entity
## dao扫描路径
module.orm.mapper-package = com.example.demo.mapper
```
因:此工具组件是服务于开发者;此诸配置项无运行期修改可能;所以只支持了单独创建一个配置文件这种方式。 :-)
5. SpringBoot项目:pom.xml Maven依赖;会自动加载启动
```
pub.cleangao
mybatis-springboot3
1.2.2
```
其中包含了springboot使用mybatis的依赖
```
org.mybatis.spring.boot
mybatis-spring-boot-starter
3.0.4
```
非SpringBoot项目:pom.xml
```
pub.cleangao
mybatis
1.2.2
```
// 启用组件;需要传入MyBatis的sqlSessionFactories
pub.cleangao.mybatisComponent.start(sqlSessionFactoryList);
## 二、注解详解
1. pub.cleangao.mybatis.annotation.Table: 用于Entity,数据表对应的实体类
2. pub.cleangao.mybatis.annotation.Column: 用于实体类中的字段,可省略(自动驼峰和下划线转换)
3. pub.cleangao.mybatis.annotation.LogicDelete: 逻辑删除字段标识
4. pub.cleangao.mybatis.annotation.PrimaryKey: 主键标识
5. pub.cleangao.mybatis.annotation.Version: 乐观锁字段标识
6. pub.cleangao.mybatis.cleavage.UseCleavage: 用在Mapper方法上的分库分表注解
7. pub.cleangao.mybatis.annotation.Database: 用于实体类上, 标识数据库类型;分库辅助注解
## 三、增删改查
#### 美中不足(设计如此):用户自定义mapper中,若存在与此组件定义同名方法,将被此组件方法覆盖。
### 1. 增
- (1)int saveAllFields(E entity); 保存,保存所有字段
- (2)int save(E entity); 保存,忽略null字段
- (3)int saveMultiSet(Collection entities); 批量保存
- (4)int saveUnique(Collection entities) 批量保存,去除重复行,通过对象是否相对判断重复数据,实体类需要实现equals方法.
- (5)int saveUnique(Collection entities, Comparator comparator) 批量保存,去除重复行,指定比较器判断
### 2. 删
- (1)int delete(E entity); 删除记录(底层根据id删除),在有逻辑删除字段的情况下,做UPDATE操作。
- (2)int deleteById(I id); 根据id删除,在有逻辑删除字段的情况下,做UPDATE操作
- (3)int deleteByQuery(Query query); 根据条件删除,在有逻辑删除字段的情况下,做UPDATE操作
- (4)int forceDelete(E entity); 强制删除(底层根据id删除),忽略逻辑删除字段,执行DELETE语句
- (5)int forceDeleteById(I id); 根据id强制删除,忽略逻辑删除字段,执行DELETE语句
- (6)int forceDeleteByQuery(Query query); 根据条件强制删除,忽略逻辑删除字段,执行DELETE语句
- (7)int deleteByIds(Collection ids); 根据多个主键id删除,在有逻辑删除字段的情况下,做UPDATE操作
- (8)int deleteByColumn(String column, Object value); 根据指定字段值删除,在有逻辑删除字段的情况下,做UPDATE操作
### 3. 改
- (1)int updateAllFields(E entity); 更新,更新所有字段
- (2)int update(E entity); 更新,忽略null字段
- (3)int updateByQuery(E entity,Query query); 根据条件更新
- (4)int updateByMap(Map map, Query query); 根据条件更新
### 4. 查
- (1)E getById(I id); 根据主键查询
- (2)E forceById(I id); 根据主键查询强制查询,忽略逻辑删除字段
- (3)E getByQuery(Query query); 根据条件查找单条记录
- (4)List listSpecificColumns(List columns,Query query); 查询返回指定的列,返回实体类集合
- (5)E getByColumn(String column, Object value); 根据字段查询一条记录
- (6)long getCount(Query query); 查询总记录数
- (7)List listByColumn(String column, Object value); 根据字段查询结果集
- (8)List list(@Param("query") Query query); 查询结果集
- (9)E getSpecificColumns(List columns, Query query); 查询单条数据并返回指定字段
- (10) T getSpecificColumns(List columns, Query query, Class clazz); 查询单条数据返回指定字段并转换到指定类中
- (11) T getColumnValue(String column, Query query, Class clazz); 查询某一行某个字段值
- (12)List listByIds(Collection ids); 根据多个主键查询
- (13)List listInArray(String column, Object[] values); 根据多个字段值查询结果集
- (14)List listInCollection(String column, Collection> values); 根据字段多个值查询结果集
- (15) List listSpecificColumns(List columns, Query query, Class clazz); 查询返回指定的列,返指定类集合
- (16) List listColumnValues(String column, Query query, Class clazz);查询指定列,返指定列集合
- (17) Page pageSpecificColumns(List columns, Query query, Class clazz); 查询返回指定的列,返回分页数据
- (18)Page page(Query query);分页查询
- (19) Page page(Query query, Class clazz); 查询结果集,并转换结果集中的记录
- (20) Page page(Query query, Class clazz); 查询结果集,并转换结果集中的记录
- (21) Page page(Query query, Supplier target); 查询结果集,并转换结果集中的记录
- (22) Page page(Query query, Function converter); 查询结果集,并转换结果集中的记录,转换处理每一行
- (23) Page pageAndConvert(Query query, Function, List> converter); 查询结果集,并转换结果集中的记录,转换处理list
- (24) Page page(Query query, Supplier target, Consumer format); 查询结果集,并转换结果集中的记录,并对记录进行额外处理
##### Query用法:
```
Query query = new Query();
query.eq("id", id);
query.eq("password",123456);
// 支持链式拼接
```
```
userMapper.page(
new Query()
.page(pageNo,3)
.force() // force忽略逻辑删除
.eq("password","123456") // 使用AND连接查询条件
.orEq("id",2) // 使用OR连接查询条件
.between("id",1,10));
```
## 四、代码生成
代码生成工具,基于 [enjoy](https://gitee.com/jfinal/enjoy) 开发;能够生成当前服务节点各层的代码。当然,DAO层是基于此组件的
详细介绍请参考本项目的codegen-springboot-mavenplugin模块
## 五、实现原理

## 六、结合Spring:AbstractRoutingDataSource的分库,和分表实现
分库分表,大体有两种实现方式:
- 代理
- 程序代码组件
使用代理的方式往往存在两方面的问题:延迟,数据Downling的中间态。而此两个缺陷是工业和互联网所不能接受的。
所以提供了本地程序代码分库分表的实现。
所有ORM框架面对的是对底层(数据库)的Java对象操作;所以,分库分表是***应用层***的事,只有应用层能确定如何拆分、计算拆分结果,使用代理等,或安置在ORM层反而是相对颠倒的架构思想;所以,依赖于Spring框架实现分库分表最好。

##### 使用方式
1. SpringBoot配置文件
```
spring:
datasource:
master:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mariadb://172.29.53.183:3306/managend?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: cleangao
password: 123456
slave:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mariadb://172.29.53.183:3306/managend?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: cleangao
password: 123456
```
使用如上方式配置多个数据源,名称任意;此处名称为masterslave
2. SpringBoot配置数据源导出
- (1) 禁用SpringBoot的数据源自动配置@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
- (2) 配置数据源导出
```
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import pub.cleangao.mybatis.springboot.DynamicDataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceConfiguration {
@Bean("ds1")
@ConfigurationProperties("spring.datasource.master")
public DataSourceProperties masterDataSourceProperties() {
return new DataSourceProperties();
}
@Bean("ds2")
@ConfigurationProperties("spring.datasource.slave")
public DataSourceProperties slaveDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean
public DynamicDataSource routingDataSource(@Qualifier("ds1") DataSourceProperties masterDataSourceProperties,
@Qualifier("ds2") DataSourceProperties slaveDataSourceProperties
) {
DynamicDataSource routingDataSource = new DynamicDataSource();
routingDataSource.setDefaultTargetDataSource(masterDataSourceProperties.initializeDataSourceBuilder().build());
Map