# 本节要点 - 认识Mybatis Plus - 学会安装Mybatis Plus插件 - 用插件生成代码 - 开启日志排查SQL # 一、什么是Mybatis Plus 官网:https://baomidou.com/ 在当今的Java开发领域,Spring Boot凭借其便捷的开发特性和强大的生态系统,成为了构建Web应用的首选框架。而MyBatis-Plus作 为MyBatis的增强工具,进一步简化了数据库操作,提高了开发效率。 !\[image-20260127103034515\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20260127103041612.png) # 二、为什么要用Mybatis Plus (JPA Hibernate) !\[image-20260122101154879\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20260122101154928.png) 自我总结: - 不需要再写哪些单表的CURD,让你快速的实现开发 - 自带分页插件(通过拦截器方式,增加sql语句的分页) - 支持主键自动生成 - 支持Lambda形式调用 \*\*mysql plus 的面试问题:\*\* 1、mybatis plus的curd的实现核心原理:注解+反射+解析xml(通过分页拦截器实现分页) 动态代理 2、原注解有哪些? - @Retention(runtime ,source,class) - @Target(method class filed type) - @Docmented 3、反射的时候获取类对象方式? - 类名 - 通过实例 - class.forName("com.woniu.UserInfoVo") \*\*(可选)\*\* \`\`\` // 1. 获取Class对象的三种方式 Class clazz1 = Dog.class; // 类名 Class clazz1 = new Dog().getClass(); // 实例方法 Class clazz1 = Class.forName("Dog"); // 全类名 // 2. 创建实例 Constructor constructor = clazz1.getConstructor(); //仅以clazz1为例 Dog dog = (Dog)constructor.newInstance(); //其实这里应该是接口Animal // 3. 获取和调用方法 Method getName = clazz1.getMethod("getName"); String name = (String) getName.invoke(dog); // 获取类上的注解 MyAnnotation classAnnotation = clazz1.getAnnotation(MyAnnotation.class); #MyAnnotation是注解类 if (classAnnotation != null) { System.out.println("类注解值: " + classAnnotation.value()); } // 获取字段上的注解 Field field = clazz1.getDeclaredField("myField"); MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class); if (fieldAnnotation != null) { System.out.println("字段注解值: " + fieldAnnotation.value()); } // 获取方法上的注解 Method method = clazz1.getMethod("myMethod"); MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class); if (methodAnnotation != null) { System.out.println("方法注解值: " + methodAnnotation.value()); } \`\`\` 为什么自带CURD? !\[image-20251015090241074\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20251015090248168.png) # 三、如何使用 ## 1、插件安装 !\[image-20250928183606662\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250928183606782.png) !\[image-20260625142901653\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20260625142901771.png) # 四、如何整合到Spring Boot ## 1、加依赖 \`\`\` mysql mysql-connector-java ${mysql.version} com.baomidou mybatis-plus-spring-boot3-starter ${mybatisplus.version} \`\`\` spring boot 以外的包自己维护一下版本 \`\`\` 17 UTF-8 UTF-8 3.2.4 1.18.24 5.3.10 8.0.20 3.5.5 \`\`\` ## 2、加配置 \`\`\` server: port: 9090 spring: application: name: xxx-demo datasource: username: root # 数据库用户名 password: daiwei # 数据库密码 # MySQL连接地址(适配8.x版本,指定时区) url: jdbc:mysql://localhost:3306/test?useUnicode=true\&characterEncoding=utf8\&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver # 8.x驱动类 mybatis-plus: # 原 MyBatis 配置保留 mapper-locations: classpath\*:mapper/\*.xml type-aliases-package: com.dw.entity configuration: map-underscore-to-camel-case: true #自动映射驼峰与数据库字段 userName -\> user_name \`\`\` 官方的初始化脚本(可选) \`\`\` spring: sql: init: schema-locations: classpath:db/schema-mysql.sql data-locations: classpath:db/data-mysql.sql mode: never \`\`\` ## 3、生成 ### 1、进入ideal里的数据库mysql连器 !\[image-20250930144410724\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930144410847.png) ### 2、配置连接信息 !\[image-20250930144834208\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930144834306.png) 注意一下时区:Asia/Shangha !\[image-20260621225202564\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/java/daiwei/20260621225209770.png) Test Connection 成功 !\[image-20260621225234379\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/java/daiwei/20260621225234498.png) ### 3、出现刚才新建的连接器 !\[image-20250930144953520\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930144953627.png) ### 4、选着要生成的表 !\[image-20250930145053124\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930145053233.png) ### 5、配置生成的代码对应的包名 !\[image-20250930145251515\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930145251614.png) ### 6、选择mybatis-plus3 ,也可以选Lombok(前提是你已经加入了Lombok的依赖) !\[image-20250930145423083\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930145423172.png) ### 7、生成的文件特别说明 - BaseMapper接口 1、所有的Mapper都必须实现整个接口 2、因为Mapper里面有mybatis plus自带的CURD方法 \`\`\` // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.baomidou.mybatisplus.core.mapper; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.exceptions.TooManyResultsException; import org.apache.ibatis.session.ResultHandler; public interface BaseMapper extends Mapper { int insert(T entity); int deleteById(Serializable id); int deleteById(T entity); default int deleteByMap(Map columnMap) { return this.delete((Wrapper)Wrappers.query().allEq(columnMap)); } int delete(@Param("ew") Wrapper queryWrapper); int deleteBatchIds(@Param("coll") Collection idList); int updateById(@Param("et") T entity); int update(@Param("et") T entity, @Param("ew") Wrapper updateWrapper); default int update(@Param("ew") Wrapper updateWrapper) { return this.update((Object)null, updateWrapper); } T selectById(Serializable id); List selectBatchIds(@Param("coll") Collection idList); void selectBatchIds(@Param("coll") Collection idList, ResultHandler resultHandler); default List selectByMap(Map columnMap) { return this.selectList((Wrapper)Wrappers.query().allEq(columnMap)); } default void selectByMap(Map columnMap, ResultHandler resultHandler) { this.selectList((Wrapper)Wrappers.query().allEq(columnMap), resultHandler); } default T selectOne(@Param("ew") Wrapper queryWrapper) { return this.selectOne(queryWrapper, true); } default T selectOne(@Param("ew") Wrapper queryWrapper, boolean throwEx) { List list = this.selectList(queryWrapper); int size = list.size(); if (size == 1) { return list.get(0); } else if (size \> 1) { if (throwEx) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + size); } else { return list.get(0); } } else { return null; } } default boolean exists(Wrapper queryWrapper) { Long count = this.selectCount(queryWrapper); return null != count \&\& count \> 0L; } Long selectCount(@Param("ew") Wrapper queryWrapper); List selectList(@Param("ew") Wrapper queryWrapper); void selectList(@Param("ew") Wrapper queryWrapper, ResultHandler resultHandler); List selectList(IPage page, @Param("ew") Wrapper queryWrapper); void selectList(IPage page, @Param("ew") Wrapper queryWrapper, ResultHandler resultHandler); List\> selectMaps(@Param("ew") Wrapper queryWrapper); void selectMaps(@Param("ew") Wrapper queryWrapper, ResultHandler\> resultHandler); List\> selectMaps(IPage\> page, @Param("ew") Wrapper queryWrapper); void selectMaps(IPage\> page, @Param("ew") Wrapper queryWrapper, ResultHandler\> resultHandler); List selectObjs(@Param("ew") Wrapper queryWrapper); void selectObjs(@Param("ew") Wrapper queryWrapper, ResultHandler resultHandler); default \> P selectPage(P page, @Param("ew") Wrapper queryWrapper) { page.setRecords(this.selectList(page, queryWrapper)); return page; } default \>\> P selectMapsPage(P page, @Param("ew") Wrapper queryWrapper) { page.setRecords(this.selectMaps(page, queryWrapper)); return page; } } \`\`\` - IService接口 1、所有的service都必须实现IService接口 2、因为IService里涵盖了对应Mapper里的CURD \`\`\` // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.baomidou.mybatisplus.extension.service; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Assert; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper; import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper; import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper; import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers; import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.springframework.transaction.annotation.Transactional; public interface IService { int DEFAULT_BATCH_SIZE = 1000; default boolean save(T entity) { return SqlHelper.retBool(this.getBaseMapper().insert(entity)); } @Transactional( rollbackFor = {Exception.class} ) default boolean saveBatch(Collection entityList) { return this.saveBatch(entityList, 1000); } boolean saveBatch(Collection entityList, int batchSize); @Transactional( rollbackFor = {Exception.class} ) default boolean saveOrUpdateBatch(Collection entityList) { return this.saveOrUpdateBatch(entityList, 1000); } boolean saveOrUpdateBatch(Collection entityList, int batchSize); default boolean removeById(Serializable id) { return SqlHelper.retBool(this.getBaseMapper().deleteById(id)); } default boolean removeById(Serializable id, boolean useFill) { throw new UnsupportedOperationException("不支持的方法!"); } default boolean removeById(T entity) { return SqlHelper.retBool(this.getBaseMapper().deleteById(entity)); } default boolean removeByMap(Map columnMap) { Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object\[0\]); return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap)); } default boolean remove(Wrapper queryWrapper) { return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper)); } default boolean removeByIds(Collection list) { return CollectionUtils.isEmpty(list) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(list)); } @Transactional( rollbackFor = {Exception.class} ) default boolean removeByIds(Collection list, boolean useFill) { if (CollectionUtils.isEmpty(list)) { return false; } else { return useFill ? this.removeBatchByIds(list, true) : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(list)); } } @Transactional( rollbackFor = {Exception.class} ) default boolean removeBatchByIds(Collection list) { return this.removeBatchByIds(list, 1000); } @Transactional( rollbackFor = {Exception.class} ) default boolean removeBatchByIds(Collection list, boolean useFill) { return this.removeBatchByIds(list, 1000, useFill); } default boolean removeBatchByIds(Collection list, int batchSize) { throw new UnsupportedOperationException("不支持的方法!"); } default boolean removeBatchByIds(Collection list, int batchSize, boolean useFill) { throw new UnsupportedOperationException("不支持的方法!"); } default boolean updateById(T entity) { return SqlHelper.retBool(this.getBaseMapper().updateById(entity)); } default boolean update(Wrapper updateWrapper) { return this.update((Object)null, updateWrapper); } default boolean update(T entity, Wrapper updateWrapper) { return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper)); } @Transactional( rollbackFor = {Exception.class} ) default boolean updateBatchById(Collection entityList) { return this.updateBatchById(entityList, 1000); } boolean updateBatchById(Collection entityList, int batchSize); boolean saveOrUpdate(T entity); default T getById(Serializable id) { return this.getBaseMapper().selectById(id); } default Optional getOptById(Serializable id) { return Optional.ofNullable(this.getBaseMapper().selectById(id)); } default List listByIds(Collection idList) { return this.getBaseMapper().selectBatchIds(idList); } default List listByMap(Map columnMap) { return this.getBaseMapper().selectByMap(columnMap); } default T getOne(Wrapper queryWrapper) { return this.getOne(queryWrapper, true); } default Optional getOneOpt(Wrapper queryWrapper) { return this.getOneOpt(queryWrapper, true); } T getOne(Wrapper queryWrapper, boolean throwEx); Optional getOneOpt(Wrapper queryWrapper, boolean throwEx); Map getMap(Wrapper queryWrapper); V getObj(Wrapper queryWrapper, Function mapper); default boolean exists(Wrapper queryWrapper) { return this.getBaseMapper().exists(queryWrapper); } default long count() { return this.count(Wrappers.emptyWrapper()); } default long count(Wrapper queryWrapper) { return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper)); } default List list(Wrapper queryWrapper) { return this.getBaseMapper().selectList(queryWrapper); } default List list(IPage page, Wrapper queryWrapper) { return this.getBaseMapper().selectList(page, queryWrapper); } default List list() { return this.list((Wrapper)Wrappers.emptyWrapper()); } default List list(IPage page) { return this.list(page, Wrappers.emptyWrapper()); } default \> E page(E page, Wrapper queryWrapper) { return this.getBaseMapper().selectPage(page, queryWrapper); } default \> E page(E page) { return this.page(page, Wrappers.emptyWrapper()); } default List\> listMaps(Wrapper queryWrapper) { return this.getBaseMapper().selectMaps(queryWrapper); } default List\> listMaps(IPage\> page, Wrapper queryWrapper) { return this.getBaseMapper().selectMaps(page, queryWrapper); } default List\> listMaps() { return this.listMaps((Wrapper)Wrappers.emptyWrapper()); } default List\> listMaps(IPage\> page) { return this.listMaps(page, Wrappers.emptyWrapper()); } default List listObjs() { return this.getBaseMapper().selectObjs((Wrapper)null); } default List listObjs(Function mapper) { return this.listObjs(Wrappers.emptyWrapper(), mapper); } default List listObjs(Wrapper queryWrapper) { return this.getBaseMapper().selectObjs(queryWrapper); } default List listObjs(Wrapper queryWrapper, Function mapper) { return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList()); } default \>\> E pageMaps(E page, Wrapper queryWrapper) { return this.getBaseMapper().selectMapsPage(page, queryWrapper); } default \>\> E pageMaps(E page) { return this.pageMaps(page, Wrappers.emptyWrapper()); } BaseMapper getBaseMapper(); Class getEntityClass(); default QueryChainWrapper query() { return ChainWrappers.queryChain(this.getBaseMapper()); } default LambdaQueryChainWrapper lambdaQuery() { return ChainWrappers.lambdaQueryChain(this.getBaseMapper(), this.getEntityClass()); } default LambdaQueryChainWrapper lambdaQuery(T entity) { return ChainWrappers.lambdaQueryChain(this.getBaseMapper(), entity); } default KtQueryChainWrapper ktQuery() { return ChainWrappers.ktQueryChain(this.getBaseMapper(), this.getEntityClass()); } default KtUpdateChainWrapper ktUpdate() { return ChainWrappers.ktUpdateChain(this.getBaseMapper(), this.getEntityClass()); } default UpdateChainWrapper update() { return ChainWrappers.updateChain(this.getBaseMapper()); } default LambdaUpdateChainWrapper lambdaUpdate() { return ChainWrappers.lambdaUpdateChain(this.getBaseMapper()); } /\*\* @deprecated \*/ @Deprecated default boolean saveOrUpdate(T entity, Wrapper updateWrapper) { return this.update(entity, updateWrapper) \|\| this.saveOrUpdate(entity); } } \`\`\` - 自己的service接口怎么写? - \*\*继承ServiceImpl接口\*\*,指定对应的Mapper和操作对象的泛型类别 - \*\*实现自己的业务接口\*\* \`\`\` public class OrderInfoServiceImpl extends ServiceImpl implements OrderInfoService{ \`\`\` 思考一下:能不能不 写 extends ServiceImpl;就只implements OrderInfoService{...}? ## 4、插入一条数据试试(步骤) 1、新建一个controler 2、注入你要插入数据对应表的service 3、构造一个和表对应的实体 4、调用service的add方法 5、再加一个查询试试 说明: \`\`\` @TableId(type = IdType.AUTO) private Long id; \`\`\` \`\`\` public enum IdType { AUTO(0), // 数据库ID自增 NONE(1), // 无状态,该类型为未设置主键类型 INPUT(2), // 用户输入ID ASSIGN_ID(3), // 分配ID(雪花算法) ASSIGN_UUID(4); // 分配UUID } \`\`\` ## 5、最重要的来了!(mapper 包扫描) \*\*1、@Mapper注解不是Spring的注解,是mybatis的;\*\* \*\*2、所以Spring的@ComponentScan不会扫描@Mapper;\*\* \*\*3、所以需要@MapperScan去扫描;@MapperScan是mybatis-spring的整合包里的注解\*\* !\[image-20250930151751046\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20250930151751126.png) !\[image-20260115122043910\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20260115122043964.png) ## 6、开启sql日志 默认集成了logback日志,直接配置就可以了 com.dw.mapper: debug 代表哪个包下的日志你要再控制台查看 \`\`\` logging: level: root: info com.dw.mapper: debug \`\`\`