欢迎光临
我们一直在努力

⚡ SQL‑First 范式 · Java 版 | SimpleDAO 企业实战教程(01)单表场景

相关开源地址:

  • 核心框架源码:https://gitee.com/gao_zhenzhong/simple-dao
  • 系统底座:https://gitee.com/gao_zhenzhong/simple-dao-starter
  • 代码生成器:https://gitee.com/gao_zhenzhong/simple-dao-coder
  • 实战案例:https://gitee.com/gao_zhenzhong/simple-dao-demo
  • 📋 前置知识

    ✅ 你只需要会❌ 你完全不需要会的
    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)

    📌 本集核心总结

  • 极简编码:实体仅两个核心注解,DAO空类继承即用,完全消灭MyBatis XML、繁杂Wrapper;
  • 自动生产能力:雪花主键、创建/修改审计、逻辑删除全部内置,零配置;
  • 统一API设计 单表、后续联表共用page/list,不存在单表/多表两套割裂开发思维;
  • SQL白盒透明 完整带参日志,无框架隐藏改写,DBA可直接优化SQL;
  • 兼容共存 可与MyBatis同项目并行,老代码不用迁移,增量接入无改造风险;
  • 分层规范 脱敏、字典翻译等业务逻辑放在Service,不侵入DAO,纠正MyBatis写TypeHandler的错误分层方式。
  • 下一集:两表联表分页查询,演示SimpleDAO统一联表API,无需ResultMap,彻底解决MyBatis联表XML臃肿难题。

    赞(0)
    未经允许不得转载:171主机测评 » ⚡ SQL‑First 范式 · Java 版 | SimpleDAO 企业实战教程(01)单表场景
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址