行业动态

了解最新公司动态及行业资讯

当前位置:首页>新闻中心>行业动态
全部 1487 公司动态 477 行业动态 504

这都可以?(告别CRUD地狱:MyBatis Plus SpringBoot重构商品管理的降维打击)商品管理,

时间:2025-07-13   访问量:1001

从3天开发到10分钟交付,优雅应对复杂业务需求的架构实践。

开篇:被CRUD支配的恐惧

深夜的办公室里,实习生小张面对满屏的SQL映射文件几近崩溃:

“第17个模糊查询接口,字段名又写错了...”

你接过键盘,看着 GoodsMapper.xml中重复的<select>、<insert>、<update>

标签——

这些千篇一律的CRUD代码,正吞噬着团队70%的开发时间

今天,你将用MyBatis Plus(MP)开启一场生产力革命。

第一章:传统MyBatis的七宗罪——为什么我们需要MP

1.1 CRUD代码的重复炼狱

<!-- 典型MyBatis映射文件片段 --> <select id="selectById" resultType="Goods"> SELECT * FROM goods WHERE id=#{id} </select> <insert id="insert" parameterType="Goods"> INSERT INTO goods(name,price) VALUES(#{name},#{price}) </insert> <!-- 20个类似方法后... -->

痛点清单

字段硬编码:数据库变更需全局搜索替换。SQL错误price拼成prcie导致生产事故。分页复杂:每个分页查询重复编写count语句。

1.2 MP的降维打击能力

MP不是语法糖,而是将CRUD抽象为声明式编程,让开发者专注业务逻辑。

第二章:10分钟极速交付——商品模块实战

下面用厨房烹饪比喻,带你感受MP的高效魔法。

2.1 食材准备:依赖配置(2分钟)

// 关键依赖 dependencies { implementation com.baomidou:mybatis-plus-boot-starter:3.5.3 implementation com.baomidou:mybatis-plus-generator:3.5.3 implementation org.freemarker:freemarker:2.3.32 // 代码生成模板 }# application.yml 核心配置 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发期SQL日志 global-config: db-config: id-type: assign_id # 分布式ID策略 logic-delete-field: deleted # 逻辑删除字段

2.2 切菜备料:实体类设计(3分钟)

@Data // Lombok自动生成getter/setter @TableName("goods") // 绑定表名 public class Goods { @TableId(type = IdType.ASSIGN_ID) // 分布式雪花ID private Long id; @TableField("goods_name") // 字段映射 @NotBlank(message = "商品名不能为空") private String name; @TableField @DecimalMin(value = "0.01", message = "价格必须≥0.01") private BigDecimal price; @TableField(fill = FieldFill.INSERT) // 自动填充 private LocalDateTime createTime; @TableLogic // 逻辑删除标记 private Integer deleted; }

设计哲学

@TableField解耦字段与列名,避免硬编码。校验注解直接嵌入实体,实现声明式数据验证。自动填充减少业务无关代码。

2.3 烹饪核心:Mapper与Service(3分钟)

// ███ 只需声明接口 ███ public interface GoodsMapper extends BaseMapper<Goods> { // 复杂查询后期扩展 @Select("SELECT * FROM goods WHERE price > #{minPrice} ORDER BY sales DESC") List<Goods> selectHotGoods(BigDecimal minPrice); } // ███ 服务层继承增强接口 ███ @Service public class GoodsService extends ServiceImpl<GoodsMapper, Goods> { // 1. 自带全套CRUD方法 // save(), removeById(), updateById(), getById(), page()... // 2. 自定义业务方法 public List<Goods> searchGoods(String keyword) { return lambdaQuery() .like(Goods::getName, keyword) .or() .apply("JSON_CONTAINS(keywords, " + keyword + ")") // JSON字段查询 .list(); } }

魔法解析Service继承树提供150+开箱即用方法,覆盖90%业务场景。

2.4 出锅装盘:控制器暴露API(2分钟)

@RestController @RequestMapping("/goods") public class GoodsController { @Autowired private GoodsService goodsService; // ███ 分页查询 ███ @GetMapping("/page") public Page<Goods> page( @RequestParam(defaultValue = "1") int current, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) String name) { return goodsService.page(new Page<>(current, size), Wrappers.<Goods>lambdaQuery() .like(StringUtils.isNotBlank(name), Goods::getName, name) ); } // ███ 逻辑删除 ███ @DeleteMapping("/{id}") public boolean delete(@PathVariable Long id) { return goodsService.removeById(id); // 自动触发逻辑删除 } }

关键进步:相比传统Controller减少70%代码量。

第三章:生产级精进——复杂业务的优雅应对

基础CRUD只是起点,真实业务需要更强大的武器库。

3.1 条件构造器:动态SQL的终极方案

public Page<Goods> complexQuery(GoodsQuery query) { return goodsService.lambdaQuery() .like(StringUtils.isNotBlank(query.getKeyword()), Goods::getName, query.getKeyword()) .gt(query.getMinPrice() != null, Goods::getPrice, query.getMinPrice()) .lt(query.getMaxPrice() != null, Goods::getPrice, query.getMaxPrice()) .in(!CollectionUtils.isEmpty(query.getCategoryIds()), Goods::getCategoryId, query.getCategoryIds()) .eq(Goods::getStatus, 1) // 上架商品 .orderByDesc(Goods::getSales) // 销量排序 .page(new Page<>(query.getPage(), query.getSize())); }

优势对比

方案

可读性

防SQL注入

代码量

XML动态SQL

需手动防

MP条件构造器

自动防护

少60%

3.2 自定义SQL:应对极端复杂场景

<!-- 位于GoodsMapper.xml --> <select id="selectGoodsWithCategory" resultType="GoodsVO"> SELECT g.*, c.name as categoryName FROM goods g LEFT JOIN category c ON g.category_id = c.id WHERE g.id = #{id} </select>// Mapper接口增强 public interface GoodsMapper extends BaseMapper<Goods> { // ███ 注解方式 ███ @Select("SELECT * FROM goods WHERE category_id = #{categoryId}") List<Goods> selectByCategory(@Param("categoryId") Long categoryId); // ███ XML方式 ███ GoodsVO selectGoodsWithCategory(Long id); }

设计平衡:80%简单操作用MP,20%复杂查询保留原生MyBatis灵活性。

3.3 多租户架构:SAAS系统必备

public class TenantInterceptor implements InnerInterceptor { @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 自动注入租户ID String sql = boundSql.getSql(); if (sql.contains("tenant_id")) return; String newSql = "SELECT * FROM (" + sql + ") tmp WHERE tenant_id = " + getCurrentTenantId(); ReflectionUtils.setFieldValue(boundSql, "sql", newSql); } }

安全策略:在SQL解析层自动隔离租户数据,避免越权风险。

第四章:工程化实践——从玩具到生产级应用

4.1 分层架构规范

src/main/java ├── controller # 控制层 ├── service # 业务层 │ ├── impl # 实现类 ├── mapper # 数据层 ├── entity # 实体类 ├── dto # 数据传输对象 │ ├── request # 入参DTO │ └── response # 出参DTO └── config # 配置类 └── MybatisPlusConfig.java

4.2 全局异常处理

@RestControllerAdvice public class GlobalExceptionHandler { // 处理数据校验异常 @ExceptionHandler(MethodArgumentNotValidException.class) public Result handleValidException(MethodArgumentNotValidException e) { BindingResult result = e.getBindingResult(); String message = result.getFieldErrors().stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining("; ")); return Result.fail(400, message); } // 处理MyBatisPlus异常 @ExceptionHandler(MybatisPlusException.class) public Result handleMybatisPlusException(MybatisPlusException e) { return Result.fail(500, "数据操作失败: " + e.getMessage()); } }

4.3 性能优化四板斧

优化点

方案

效果

分页插件

启用PageOptimize模式

减少1次count查询

二级缓存

整合Redis+注解@CacheNamespace

查询速度提升8倍

批量操作

saveBatch()设置批次大小1000

插入速度提升15倍

SQL打印

生产环境关闭log-impl

降低CPU消耗30%

第五章:代码生成器——终结重复劳动的核武器

5.1 生成器配置(核心代码)

FastAutoGenerator.create(dataSourceConfig) .globalConfig(builder -> builder.author("DevSquad") // 作者 .outputDir("D://gen-code") // 输出目录 .enableSwagger() // 开启swagger ) .packageConfig(builder -> builder.parent("com.example.mall") // 包名 .moduleName("product") // 模块名 ) .strategyConfig(builder -> builder.addInclude("goods", "category") // 表名 .entityBuilder().enableLombok() // 实体策略 .controllerBuilder().enableRestStyle() // REST风格 .mapperBuilder().enableMapperAnnotation() // @Mapper ) .templateEngine(new FreemarkerTemplateEngine()) // 模板引擎 .execute();

5.2 生成效果

D://gen-code ├── goods │ ├── GoodsController.java │ ├── GoodsService.java │ ├── GoodsServiceImpl.java │ ├── GoodsMapper.java │ ├── Goods.java # 实体类 │ └── GoodsDTO.java # DTO对象 └── category # 相同结构

效率对比:手动创建1个实体模块需30分钟 → 生成器10秒完成。

终章:CRUD的涅槃重生

当小张看到自动生成的代码时,眼睛亮了起来:

“原来商品模块可以这么快完成!”

你指着屏幕上的分层代码说:

“记住,真正强大的不是框架本身,而是它让我们摆脱低级重复,

将创造力倾注在真正改变业务的复杂逻辑上”。

系列预告

下一篇:《SpringCloud alibaba:微服务架构生死局》。

上一篇:学会了吗(Labubu引爆“娃衣”经济:网店月售近万,兼职手作成新蓝海二战期间,犹太女人被纳粹疯狂摧残老照片,尘封70年如今依旧胆颤)网店设计,

下一篇:深度揭秘(广东碳标签信息化管理平台上线、十五运特许商品碳标签启动,来看……)商品管理,

在线咨询

点击这里给我发消息 售前咨询专员

点击这里给我发消息 售后服务专员

在线咨询

免费通话

24小时免费咨询

请输入您的联系电话,座机请加区号

免费通话

微信扫一扫

微信联系
返回顶部