一、前言前面四篇我们已经学会了CRUD 建表 表关系 JOIN但到这里其实还只是数据库层面真正的企业开发还差最后一步❗ SQL 如何接入 Spring Boot 项目很多初学者学 SQL 时有个问题会写 SQL 不会落项目比如SQL 写在哪里JOIN 写在哪里Service 能不能直接写 SQLMyBatis-Plus 到底干嘛的XML 为什么企业还在用这一篇我们把这些问题一次讲透。二、企业里的真实调用链先看真实项目里的结构Controller ↓ Service业务 事务 缓存 ↓ QueryMapper复杂 JOIN ↓ Mapper单表 CRUD ↓ 数据库这一套非常重要。后面你做 Spring Boot 项目基本都会围绕这个结构展开。三、为什么 SQL 不能写在 Service很多新手最开始会这样写Service public class UserService { Resource private JdbcTemplate jdbcTemplate; public UserDetailVO getUserDetail(Long id) { String sql SELECT ... ; return jdbcTemplate.queryForObject(sql, ...); } }虽然能跑。但问题很大1️⃣ Service 职责混乱Service 本来应该负责业务逻辑 事务 缓存结果现在SQL 也塞进来了会越来越乱。2️⃣ SQL 无法复用以后别的接口也要查用户详情你只能复制 SQL。3️⃣ JOIN SQL 很快会失控企业里的 JOIN几十行 上百行Service 根本没法看。四、企业里的正确做法Mapper 分层所以企业里通常会这样分1️⃣ Mapper单表 CRUD负责简单增删改查例如userMapper.selectById(id); userMapper.insert(user);2️⃣ QueryMapper复杂 JOIN负责联表查询 复杂 SQL 统计查询例如userQueryMapper.selectUserDetailById(id);五、企业真实结构推荐这里给你一个接近企业的结构。user 模块user/ ├── controller/ ├── service/ ├── converter/ ├── model/ │ ├── dto/ │ ├── vo/ │ └── entity/ └── infrastructure/ └── persistence/ └── mapper/ ├── UserMapper.java ├── UserQueryMapper.java └── xml/ └── UserQueryMapper.xml六、Mapper 到底干什么UserMapper.javaMapper public interface UserMapper { int insert(User user); User selectById(Long id); int updateById(User user); int deleteById(Long id); }这里只做单表 CRUD七、MyBatis-Plus 为什么企业喜欢用因为单表 CRUD 太重复了比如insert delete update selectById几乎每张表都有。所以 MyBatis-Plus 帮你自动生成。示例public interface UserMapper extends BaseMapperUser { }然后直接userMapper.selectById(id); userMapper.insert(user);就能用。八、为什么复杂 JOIN 企业还是喜欢 XML很多人第一次学 MyBatis-Plus 会以为以后不用写 SQL 了其实不是。企业真实情况简单 CRUDMyBatis-Plus复杂查询XML原因因为 JOIN 很复杂。例如SELECT u.id, u.username, d.real_name, a.receiver_name, a.phone FROM user u LEFT JOIN user_detail d ON u.id d.user_id LEFT JOIN user_address a ON u.id a.user_id WHERE u.id #{id}这种 SQLXML 更清晰 更容易维护 更容易优化九、企业里的 QueryMapper接口Mapper public interface UserQueryMapper { UserDetailVO selectUserDetailById(Long id); }XMLselect idselectUserDetailById resultTypecom.example.vo.UserDetailVO SELECT u.id, u.username, d.real_name, a.receiver_name, a.phone, a.detail_address FROM user u LEFT JOIN user_detail d ON u.id d.user_id LEFT JOIN user_address a ON u.id a.user_id WHERE u.id #{id} /select十、Service 真正该做什么Service 不负责写 SQL。Service 负责业务逻辑 事务 缓存 调用 Mapper示例Service public class UserServiceImpl { Resource private UserQueryMapper userQueryMapper; public UserDetailVO getUserDetail(Long id) { return userQueryMapper .selectUserDetailById(id); } }十一、企业里的缓存Redis企业里通常不会每次都查数据库。例如用户详情页访问频率非常高。所以会先查 Redis 没有再查数据库示例public UserDetailVO getUserDetail(Long userId) { String key user:detail: userId; // 1. 查缓存 UserDetailVO cached redis.get(key); if (cached ! null) { return cached; } // 2. 查数据库 UserDetailVO vo userQueryMapper.selectUserDetailById(userId); // 3. 写缓存 redis.set(key, vo); return vo; }十二、这一篇真正的核心这一篇最重要的不是MyBatis-Plus XML而是❗ SQL 在企业里不是单独存在的而是 进入“分层架构”十三、企业里的 SQL 最终分工CRUDMyBatis-PlusJOINXML业务逻辑Service事务Transactional缓存Redis十四、一句话总结企业里的 SQL 不是“随便写”而是“分层 分职责 分复杂度”下一篇SQL 第六篇索引入门为什么你的查询越来越慢我们会真正讲透索引 B树 user_id 为什么加索引 EXPLAIN以及企业里到底哪些字段需要索引