相关开源地址:
📋 前置知识
| Java 基础(类、注解、泛型) | MyBatis/MP、复杂ORM插件 |
| 基础SQL(SELECT、WHERE、JOIN) | XML动态标签、OGNL表达式 |
| Spring Boot基础配置 | Spring高级自动配置、复杂Maven配置 |
| IDE运行Maven项目 | 繁琐框架适配调试 |
📚 全套教程总览
| 01 · 单表 CRUD + 审计 + 逻辑删除 | 约 6 min | 零代码单表操作、自动填充审计、内置逻辑删除 |
| 02 · 联表查询 + 分页 | 约 5 min | 单/多表统一API,无需ResultMap |
| 03 · 条件进阶:IN + 子查询 | 约 5 min | 替代MyBatis foreach标签,动态片段拼接 |
| 04 · 多表联查 + 复杂条件 | 约 5 min | 多表关联、区间筛选通用写法 |
| 05 · 报表聚合:GROUP BY + 聚合函数 | 约 6 min | 原生SQL报表无限制,不受ORM束缚 |
| 06 · mergeParams 多组条件合并 | 约 6 min | 复杂报表拆分多条件,解耦复用 |
| 07 · 多租户 + 数据权限 · AOP 破局 | 约 7 min | 不用MyBatis拦截器,Spring原生AOP扩展 |
| 08 · 脱敏 + 审计扩展 · 框架不设限 | 约 7 min | 纠正MyBatis持久层脱敏错误分层思路 |
🚀 项目快速上手
本案例内置H2内存库,无需安装本地数据库,克隆案例直接启动即可运行。
完整项目层级结构
│ pom.xml // 项目依赖,仅少量核心包,无冗余插件
│
├─src
│ └─main
│ ├─java
│ │ └─example
│ │ │ DemoApplication.java // 启动类,内置全套测试逻辑
│ │ └─user // 用户模块分层
│ │ User.java // 数据库实体
│ │ UserCond.java // 动态条件载体
│ │ UserDao.java // 数据访问层
│ │
│ └─resources
│ application.yml // 极简数据源配置
│ logback-spring.xml // SQL日志打印配置
│ schema.sql // 自动建表脚本
1. Maven依赖 pom.xml
说明:仅依赖Spring JDBC + SimpleDAO核心,抛弃MyBatis整套XML、插件生态,依赖体积大幅缩减,同等业务代码量仅MyBatis 1/3~1/4。
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.11</version>
<relativePath />
</parent>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<!– Spring JDBC底层底座,SimpleDAO基于此增强 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!– SimpleDAO核心持久层框架 –>
<dependency>
<groupId>com.simple</groupId>
<artifactId>simple-dao</artifactId>
<version>1.2.0</version>
</dependency>
<!– H2内存数据库,本地运行无需装库 –>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!– Lombok简化实体代码 –>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. 配置文件 application.yml
说明:无框架专属复杂配置,仅标准Spring数据源,自动执行建表脚本,开箱即用。
spring:
datasource:
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=–1
driver-class-name: org.h2.Driver
username: sa
password:
sql:
init:
schema-locations: classpath:schema.sql
mode: always
# 可选:开启完整可执行SQL日志
simple-dao.show-sql: true
3. 建表脚本 schema.sql
说明 内置标准业务字段:通用审计字段、dr逻辑删除标记,框架自动识别处理,无需额外配置。
— 用户业务表,包含自动审计、逻辑删除通用字段
CREATE TABLE IF NOT EXISTS sys_user (
id BIGINT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INTEGER,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20) UNIQUE,
password VARCHAR(64) NOT NULL,
sex TINYINT, — 1男 2女
avatar VARCHAR(255),
status TINYINT DEFAULT 1, — 1正常 0禁用
birthday DATE,
address VARCHAR(255),
user_type TINYINT DEFAULT 1, — 1普通 2管理员
remark VARCHAR(500),
create_time TIMESTAMP,
create_by BIGINT,
update_time TIMESTAMP,
update_by BIGINT,
dr TINYINT DEFAULT 0 — 逻辑删除标识,框架自动识别
);
🔧 核心四层业务代码演示
第一层:实体 User.java
说明 仅@Table绑定表、@Id定义主键,自动映射下划线字段;createTime、dr等审计/删除字段无需手动赋值,save/update自动填充。
package example.user;
import com.simple.common.base.annotation.Id;
import com.simple.common.base.annotation.Table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "【用户表】实体")
@Table("sys_user") // 注解绑定数据库表名
public class User {
@Id // 默认雪花分布式主键,无需手动生成ID
@Schema(description = "主键ID")
private Long id;
@Schema(description = "用户名")
private String name;
@Schema(description = "年龄")
private Integer age;
@Schema(description = "邮箱")
private String email;
@Schema(description = "手机号")
private String phone;
@Schema(description = "密码")
private String password;
@Schema(description = "性别 1男 2女")
private Byte sex;
@Schema(description = "头像地址")
private String avatar;
@Schema(description = "状态 1正常 0禁用")
private Byte status;
@Schema(description = "生日")
private LocalDate birthday;
@Schema(description = "地址")
private String address;
@Schema(description = "用户类型 1普通 2管理员")
private String remark;
// 框架自动填充,业务无需赋值,前端隐藏字段
@Schema(hidden = true)
private LocalDateTime createTime;
@Schema(hidden = true)
private Long createBy;
@Schema(hidden = true)
private LocalDateTime updateTime;
@Schema(hidden = true)
private Long updateBy;
// dr存在自动走逻辑删除,无该字段执行物理删除
@Schema(hidden = true)
private Byte dr;
}
第二层:条件类 UserCond.java
说明 彻底抛弃MyBatis <if>、<foreach> XML标签,纯Java方法拼接条件;参数为空自动忽略,3代表前后模糊匹配,in方法自动生成占位符。
package example.user;
import java.time.LocalDate;
import com.simple.common.base.BaseCondition;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import io.swagger.v3.oas.annotations.media.Schema;
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "用户查询条件载体")
public class UserCond extends BaseCondition {
// 页面入参字段
private Integer ageMax;
private Integer ageMin;
private String name;
private String email;
private String phone;
private Byte sex;
private Byte dr;
private Object[] ids;
/** 重写拼接方法,统一组装所有查询条件 */
@Override
protected void addCondition() {
and("name LIKE", name, 3); // 数字3 = %内容% 自动模糊,无需手动拼接%
and("age =", age);
and("age >=", ageMin); // 不传ageMin自动忽略该条件,不用写if判断
and("age <=", ageMax);
and("email LIKE", email, 3);
and("dr =", dr);
in("id", ids); // 自动生成IN(?,?,?),替代MyBatis foreach标签
}
}
第三层:DAO层 UserDao.java
说明 核心优势:空类继承BaseDao直接拥有50+通用方法,无需写任何单表SQL;MyBatis需要BaseMapper+大量XML,两套写法思维割裂,这里完全统一。
package example.user;
import com.simple.common.base.BaseDao;
import org.springframework.stereotype.Repository;
/**
* 仅继承泛型父类,零代码拥有单表新增、批量、分页、删除全套能力
* 单表、联表共用一套page/list API,无思维割裂
**/
@Repository
public class UserDao extends BaseDao<User> {
// 无任何自定义代码,自动获得CRUD、分页、批量、行锁等能力
}
第四层:启动测试类 DemoApplication.java
说明 @PostConstruct启动自动执行全套单表流程,日志打印完整可复制SQL,无框架黑盒;自动填充创建人、时间、逻辑删除标识。
package example;
import com.simple.common.base.Page;
import example.user.User;
import example.user.UserCond;
import example.user.UserDao;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.time.LocalDate;
import java.util.List;
@Slf4j
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
private static final Byte BYTE_1 = Byte.valueOf("1");
private static final Byte BYTE_0 = Byte.valueOf("0");
@Autowired
private UserDao userDao;
// 项目启动自动执行全套CRUD演示流程
@PostConstruct
public void demo() {
log.info("===== SimpleDAO 单表完整演示 ====");
// 1.单条新增:自动雪花ID、自动填充createTime/createBy、dr=0
log.info("1. 单条插入用户");
User user = User.builder().name("张三").age(25).email("zhangsan@QQ.com")
.phone("13800138000").password("123456").sex(BYTE_1)
.status(BYTE_1).birthday(LocalDate.now()).address("北京").build();
userDao.save(user);
// 2.批量新增:批量语句自动填充审计字段,无需循环赋值
log.info("2. 批量插入多条用户");
userDao.saveBatch(List.of(
User.builder().name("李四").age(28).email("lisi@QQ.com").phone("13900139000")
.password("123456").sex(BYTE_1).birthday(LocalDate.now()).address("上海").build(),
User.builder().name("王五").age(30).email("wangwu@QQ.com").phone("13700137000")
.password("123456").sex(BYTE_1).birthday(LocalDate.now()).address("广州").build()
));
// 3.主键查询,直接返回完整实体
log.info("3. 根据ID查询单条数据");
User u = userDao.findById(user.getId());
log.info("查询结果:{}", u);
// 4. 条件分页,自动生成count统计SQL + limit分页SQL
log.info("4. 模糊+区间条件分页查询");
Page<User> page = userDao.page(UserCond.builder().name("张").ageMin(20).ageMax(30).build());
log.info("总条数:{}", page.getRowCount());
page.getDataList().forEach(item -> log.info("分页数据:{}", item));
// 5. 更新:仅更新非空字段,自动刷新updateTime/updateBy
log.info("5. 修改用户年龄");
u.setAge(26);
userDao.update(u);
log.info("更新后数据:{}", userDao.findById(u.getId()));
// 6. 逻辑删除:检测到dr字段,执行UPDATE dr=1而非DELETE
log.info("6. 执行逻辑删除");
userDao.delete(u.getId());
// 7. 查询未删除有效数据
log.info("7. 查询正常未删除用户");
userDao.list(UserCond.builder().dr(BYTE_0).build()).forEach(item -> log.info("有效用户:{}", item));
}
}
📝 运行日志效果(完整可执行SQL)
说明 SimpleDAO打印带真实参数完整SQL,直接复制到数据库客户端运行;MyBatis仅输出占位符SQL,需要手动替换参数调试。
# 插入日志,自动填充雪花ID、创建时间、创建人
[INFO]INSERT INTO sys_user (id,name,age,email,phone,password,sex,avatar,status,birthday,address,user_type,remark,create_time,create_by,dr) VALUES (3679201737291333632,'张三',25,'zhangsan@QQ.com','13800138000','123456',1,'https://www.gzz.com',1,'2026-04-10','北京',1,'牛逼-plus','2026-04-10 13:14:10',1000,0)
# 分页自动生成count + 查询两条SQL
[INFO]SELECT COUNT(1) FROM sys_user t WHERE t.name LIKE '%张%' AND t.age >= 20 AND t.age <= 30
[INFO]SELECT t.id,t.name,t.age,t.email,t.phone,t.password,t.sex,t.avatar,t.status,t.birthday,t.address,t.user_type,t.remark,t.create_time,t.create_by,t.update_time,t.update_by,t.dr FROM sys_user t WHERE t.name LIKE '%张%' AND t.age >= 20 AND t.age <= 30 LIMIT 0,10
# 更新自动更新update_time
[INFO]UPDATE sys_user t SET t.name = '张三',t.age = 26,t.email = 'zhangsan@QQ.com',t.phone = '13800138000',t.password = '123456',t.sex = 1,t.avatar = 'https://www.gzz.com',t.status = 1,t.birthday = '2026-04-10',t.address = '北京',t.user_type = 1,t.remark = '牛逼-plus',t.update_time = '2026-04-10 13:14:10',t.update_by = 1000,t.dr = 0 WHERE id=3679201737291333632
# 删除执行逻辑更新,而非物理删除
[INFO]UPDATE sys_user t SET dr=1 WHERE id IN (3679201737291333632)
📌 本集核心总结
下一集:两表联表分页查询,演示SimpleDAO统一联表API,无需ResultMap,彻底解决MyBatis联表XML臃肿难题。



