Mybatis Plus详细使用讲解

MyBatis Plus 使用详解


一、添加依赖与配置 MySQL

1. 添加依赖(Maven)
<!-- MyBatis Plus 核心依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>
2. Mybatis Plus的详细yml配置
# application.yml

# 数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus_demo?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

# MyBatis Plus 配置(继承 MyBatis 原生配置)
mybatis-plus:
  # 全局配置(核心配置)
  global-config:
    db-config:
      id-type: auto             # 主键策略:AUTO(数据库自增)、INPUT(手动输入)、ASSIGN_ID(雪花算法)
      logic-delete-field: deleted  # 逻辑删除字段名(实体类字段名)
      logic-delete-value: 1     # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
      table-underline: true     # 表名是否使用下划线命名(默认 true)
      column-underline: true    # 字段名是否使用下划线命名(默认 true)
  configuration:
    map-underscore-to-camel-case: true  # 自动驼峰命名规则(默认 true)
    cache-enabled: true          # 开启二级缓存(默认 true)
    lazy-loading-enabled: true   # 延迟加载(默认 false)
    aggressive-lazy-loading: false # 侵略性延迟加载(默认 false)
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志实现(控制台打印 SQL)
  
  # MyBatis 原生配置(继承关系)
  mapper-locations: classpath*:/mapper/**/*.xml  # XML 映射文件路径
  type-aliases-package: com.example.entity       # 实体类别名包路径
  type-handlers-package: com.example.handler     # 类型处理器包路径

  # 插件配置(需配合 Java Config 使用)
  # 注意:以下插件需在配置类中通过 @Bean 注入
  # 分页插件(必须配置)
  # 性能分析插件(开发环境使用)
  # 乐观锁插件

二、CRUD 实现与代码示例

1. 实体类定义

在这里插入图片描述

@Data
@TableName("user") // 表名映射(默认类名驼峰转下划线)
public class User {
    @TableId(type = IdType.AUTO) // 主键自增
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
2. Mapper 接口继承 BaseMapper

无需编写 XML,继承 BaseMapper 即可获得 CRUD 方法

public interface UserMapper extends BaseMapper<User> {
    // 无需编写 XML,继承 BaseMapper 即可获得 CRUD 方法
}
3. CRUD 操作代码示例

在这里插入图片描述

@Autowired
private UserMapper userMapper;

// 插入
User user = new User();
user.setName("张三");
user.setAge(25);
user.setEmail("zhangsan@example.com");
userMapper.insert(user); // 返回影响行数

// 查询(根据ID)
User user = userMapper.selectById(1L);

// 查询所有
List<User> users = userMapper.selectList(null);

// 条件查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("age", 25);
List<User> userList = userMapper.selectList(wrapper);

// 更新
user.setAge(30);
userMapper.updateById(user); // 根据ID更新

// 删除
userMapper.deleteById(1L);

三、条件构造器(Wrapper)详解

1. 核心类说明
  • QueryWrapper:普通条件构造器(字段名硬编码)
  • LambdaQueryWrapper:Lambda 表达式条件构造器(避免字段名硬编码)(推荐)
2. 常用条件方法
方法名作用示例
eq等于eq("name", "张三")
ne不等于ne("status", 0)
gt大于gt("age", 18)
between范围查询between("age", 20, 30)
like模糊查询like("name", "张%")
in包含in("id", Arrays.asList(1, 2, 3))
orderByAsc升序排序orderByAsc("age")
select指定查询字段select("id", "name")
3. 代码示例
// 1. 查询年龄大于20且邮箱包含"example"的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 20)
       .like("email", "example")
       .orderByDesc("id");
List<User> users = userMapper.selectList(wrapper);

// 2. 使用 Lambda 表达式(避免字段名硬编码)
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.gt(User::getAge, 20)
             .like(User::getEmail, "example")
             .orderByDesc(User::getId);
List<User> lambdaUsers = userMapper.selectList(lambdaWrapper);

// 3. 复杂组合条件(AND/OR)
wrapper.and(w -> w.eq("name", "张三").or().eq("name", "李四"))
       .between("age", 20, 30);

四、分页插件使用详解

1. 配置分页插件
@Configuration
public class MyBatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件(数据库类型需指定)
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
2. 分页查询代码示例
// 1. 创建分页对象(当前页, 每页数量)
Page<User> page = new Page<>(1, 10); 

// 2. 执行分页查询(传入分页对象和查询条件)
Page<User> result = userMapper.selectPage(page, null);

// 3. 获取结果
System.out.println("总记录数: " + result.getTotal());
System.out.println("当前页数据: " + result.getRecords());

// 4. 自定义分页查询(如关联多表)
userMapper.selectUserPage(page, wrapper); // 需在Mapper中定义SQL

五、代码生成器详解

1. 添加依赖
<!-- 代码生成器 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3.1</version>
</dependency>

<!-- 模板引擎(Freemarker) -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>
2. 生成器配置代码
public class CodeGenerator {
    public static void main(String[] args) {
        AutoGenerator generator = new AutoGenerator();

        // 1. 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        globalConfig.setAuthor("YourName");
        globalConfig.setOpen(false); // 生成后不打开文件夹
        globalConfig.setFileOverride(true); // 覆盖旧文件
        generator.setGlobalConfig(globalConfig);

        // 2. 数据源配置
        DataSourceConfig dataSource = new DataSourceConfig();
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis_plus_demo?useSSL=false");
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        generator.setDataSource(dataSource);

        // 3. 包路径配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.example"); // 父包名
        packageConfig.setEntity("entity");      // 实体类包名
        packageConfig.setMapper("mapper");     // Mapper包名
        generator.setPackageInfo(packageConfig);

        // 4. 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel); // 表名转驼峰
        strategy.setColumnNaming(NamingStrategy.underline_to_camel); // 列名转驼峰
        strategy.setEntityLombokModel(true);   // 使用Lombok
        strategy.setInclude("user", "order");  // 指定生成哪些表
        strategy.setRestControllerStyle(true);  // 生成@RestController
        generator.setStrategy(strategy);

        // 5. 执行生成
        generator.setTemplateEngine(new FreemarkerTemplateEngine());
        generator.execute();
    }
}
3. 生成结果

运行 main 方法后,会自动生成以下文件:

  • User.java(实体类)
  • UserMapper.java(Mapper接口)
  • UserMapper.xml(XML文件,默认无内容,需自定义SQL)
  • UserService.java(Service接口)
  • UserServiceImpl.java(Service实现类)

六、继承 IService 的核心步骤

一. 继承父类接口

可以简化在service层的代码书写,前提是需要让Mapper层继承BaseMapper< >,让Service继承Iservice<>

1. 创建实体类(Entity)

定义与数据库表对应的实体类,使用 MyBatis Plus 注解:

@Data
@TableName("user") // 指定表名(若表名与类名一致可省略)
public class User {
    @TableId(type = IdType.AUTO) // 主键自增
    private Long id;
    private String name;
    private Integer age;
    private String email;
    
    @TableField(fill = FieldFill.INSERT) // 自动填充创建时间
    private LocalDateTime createTime;
    
    @TableLogic // 逻辑删除标记
    private Integer deleted;
}
2. 创建 Mapper 接口

Mapper 接口继承 BaseMapper<T>,无需编写 XML:

public interface UserMapper extends BaseMapper<User> {
    // 可在此定义自定义 SQL 方法(需配合 XML 或注解)
}
3. 定义 Service 接口

Service 接口继承 IService<T>,声明通用方法 + 自定义业务方法:

public interface UserService extends IService<User> {
    
    // 自定义方法示例:查询活跃用户列表
    List<User> findActiveUsers();
    
    // 自定义方法示例:分页查询成年人
    Page<User> pageAdults(Page<User> page);
}
4. 实现 Service 接口

实现类继承 ServiceImpl<M, T>,并实现自定义方法:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    // 实现自定义方法:查询活跃用户(status=1)
    @Override
    public List<User> findActiveUsers() {
        return this.lambdaQuery()
                .eq(User::getStatus, 1)
                .list();
    }

    // 实现自定义方法:分页查询成年人(age >= 18)
    @Override
    public Page<User> pageAdults(Page<User> page) {
        return this.page(page, 
            new LambdaQueryWrapper<User>().ge(User::getAge, 18)
        );
    }
}

二、IService 核心方法详解

1. 基础 CRUD 方法
方法名作用示例
save(T entity)插入单条记录userService.save(user)
saveBatch(List<T> list)批量插入userService.saveBatch(userList)
removeById(Serializable id)根据 ID 删除userService.removeById(1L)
updateById(T entity)根据 ID 更新userService.updateById(user)
getById(Serializable id)根据 ID 查询User user = userService.getById(1L)
list()查询所有记录List<User> users = userService.list()
list(Wrapper<T> wrapper)条件查询列表userService.list(wrapper)
2. 链式查询(Lambda 风格)
// 查询年龄大于18且邮箱包含"example"的用户
List<User> users = userService.lambdaQuery()
        .gt(User::getAge, 18)
        .like(User::getEmail, "example")
        .list();

// 更新所有名字以"张"开头的用户的年龄
boolean updated = userService.lambdaUpdate()
        .set(User::getAge, 25)
        .likeRight(User::getName, "张")
        .update();
3. 分页查询
// 分页查询(需先配置分页插件)
Page<User> page = new Page<>(1, 10); // 当前页, 每页数量
Page<User> result = userService.page(page, 
    new LambdaQueryWrapper<User>().orderByDesc(User::getCreateTime)
);

// 获取分页结果
System.out.println("总记录数: " + result.getTotal());
System.out.println("当前页数据: " + result.getRecords());
4. 批量操作
// 批量插入(每批 1000 条)
userService.saveBatch(userList, 1000);

// 批量更新(根据 ID)
userService.updateBatchById(userList);

// 批量删除(根据 ID 列表)
userService.removeByIds(Arrays.asList(1L, 2L, 3L));

三、自定义业务方法扩展

1. 结合自定义 Mapper 方法

如果操作需要复杂 SQL,可在 Mapper 中定义,并在 Service 中调用:

Mapper 接口

public interface UserMapper extends BaseMapper<User> {
    // 自定义查询(如联表查询)
    List<User> selectUserWithRole(Long userId);
}

Service 实现类

@Override
public List<User> findActiveUsers() {
    // 调用自定义 Mapper 方法
    return baseMapper.selectUserWithRole(1L);
}
2. 覆盖默认方法

修改默认 CRUD 逻辑(如添加数据校验):

@Override
public boolean save(User user) {
    // 自定义校验逻辑
    if (user.getName() == null) {
        throw new RuntimeException("用户名不能为空");
    }
    return super.save(user);
}

四、事务管理与注解

1. 开启事务

默认情况下,MyBatis Plus 不自动开启事务,需手动添加 @Transactional

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Transactional // 添加事务注解
    @Override
    public void transferBalance(Long fromUserId, Long toUserId, BigDecimal amount) {
        userMapper.deductBalance(fromUserId, amount);
        userMapper.addBalance(toUserId, amount);
    }
}
2. 事务传播行为

通过 @Transactional(propagation = Propagation.REQUIRED) 指定事务传播级别。


五、最佳实践

1. 严格分层架构
  • Controller 层:处理 HTTP 请求,调用 Service 方法。
  • Service 层:实现业务逻辑,调用 Mapper 或组合多个 Service。
  • Mapper 层:仅负责数据库操作。
2. 避免过度封装
  • 简单操作:直接使用 IService 提供的方法。
  • 复杂操作:优先在 Service 层组合多个方法,或使用自定义 Mapper。
3. 性能优化
  • 批量操作:使用 saveBatch/updateBatchById 代替循环单条操作。
  • 分页查询:避免不必要的大数据量分页(如 PagesearchCount 配置)。

六、完整代码示例

Controller 层
@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public User getById(@PathVariable Long id) {
        return userService.getById(id);
    }

    @PostMapping("/save")
    public boolean save(@RequestBody User user) {
        return userService.save(user);
    }
}
Service 层完整实现
public interface UserService extends IService<User> {
    List<User> findAdults();
    Page<User> pageAdults(Page<User> page);
    List<User> findVIPUsers();
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Override
    public List<User> findAdults() {
        return this.lambdaQuery().ge(User::getAge, 18).list();
    }

    @Override
    public Page<User> pageAdults(Page<User> page) {
        return this.page(page, new LambdaQueryWrapper<User>().ge(User::getAge, 18));
    }

    @Override
    public List<User> findVIPUsers() {
        return baseMapper.selectVIPUsers(); // 调用 Mapper 中的自定义方法
    }
}

七、常见问题解决

1. Service 方法不生效
  • 检查是否添加了 @Service 注解。
  • 确保 Service 实现类继承了 ServiceImpl<M, T>
2. 事务不回滚
  • 确认方法是否为 public
  • 检查是否在同一个类中调用事务方法(避免自调用)。
3. 字段映射失败
  • 检查 @TableField 注解的 value 属性是否与数据库字段名一致。
  • 确认 application.ymlmap-underscore-to-camel-case 配置是否开启。

通过继承 IService,开发者可以快速构建出功能强大且易于维护的 Service 层,既能享受 MyBatis Plus 的便捷性,又能灵活扩展业务逻辑。


通过以上步骤,可快速掌握 MyBatis Plus 的核心功能。实际开发中可结合官方文档进一步优化配置。MybatisPlus官网:官网地址

### MyBatis Plus 源码详解 #### 1. MyBatis Plus 的核心概念 MyBatis Plus 是基于 MyBatis 进行二次封装的一个简化操作数据库的增强工具[^2]。它不仅保留了 MyBatis 原有的灵活性,还提供了更多便捷的功能来提高开发效率。 #### 2. 主要功能模块解析 ##### 2.1 `SqlParser` 解析器 为了支持更多的 SQL 特性和优化查询性能,MyBatis Plus 提供了一个强大的 SQL 解析机制。通过自定义 SQL 注解和内置模板引擎的支持,开发者能够更加灵活地编写复杂的业务逻辑所需的 SQL 语句[^1]。 ##### 2.2 `MetaObject` 元对象处理 继承并扩展了 MyBatis 中用于管理实体类属性映射的核心组件——`MetaObject`,使得在不侵入原有代码结构的情况下实现了对 JavaBean 属性更细粒度的操作控制。 ```java // MetaObject 使用示例 public class User { private Long id; private String name; public static void main(String[] args) { User user = new User(); MetaObject metaObject = SystemMetaObject.forObject(user); metaObject.setValue("name", "test"); System.out.println(metaObject.getValue("name")); } } ``` ##### 2.3 表名与字段自动识别 借助于注解方式实现表名以及列名到实体类成员变量之间的双向绑定关系维护工作自动化。例如,在实体类上添加 `@TableName` 来指定对应的数据库表格名称[^3]: ```java @TableId(type = IdType.AUTO) private Integer id; // 自增主键 @ApiModelProperty(value = "批次详情ID") @Schema(description = "批次详情ID") @TableField(fill = FieldFill.INSERT_UPDATE) private Long batchDetailId; ``` #### 3. 插件体系架构设计 插件化的设计理念贯穿整个框架之中,允许第三方开发者轻松集成各种实用特性而无需修改内核代码。比如分页插件、乐观锁插件等都是利用这一特点构建而成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值