ITPub博客

首页 > 应用开发 > Java > Mybatis-Plus 实战指南:核心功能解析与最佳实践

Mybatis-Plus 实战指南:核心功能解析与最佳实践

Java 作者:bhluo 时间:2025-11-19 10:53:08 0 删除 编辑

# Mybatis-Plus 实战指南:核心功能解析与最佳实践


Mybatis-Plus是MyBatis的强大增强工具,在保留MyBatis所有特性的基础上,提供了丰富的功能简化开发、提高效率。本文将深入探讨Mybatis-Plus的核心功能和使用实践。


## Mybatis-Plus 核心架构


Mybatis-Plus在MyBatis基础上进行了深度封装,主要包含以下核心模块:


- **核心模块**:提供基础CRUD操作、条件构造器等功能

- **代码 生成器**:自动化生成Entity、Mapper、Service等代码

- **分页插件**:简化分页查询操作

- **性能分析插件**:监控SQL执行性能


## 项目配置与集成


### 依赖配置


```xml

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus-boot-starter</artifactId>

    <version>3.5.3.1</version>

</dependency>

<"lker.jiebaobifen.com">

<"tyjg.jiebaobifen.com">

<"wtsa.jiebaobifen.com">

```


### 基础配置类


```java

@Configuration

@MapperScan("com.example.mapper")

public class MybatisPlusConfig {


    @Bean

    public MybatisPlusInterceptor mybatisPlusInterceptor() {

        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        

        // 添加分页插件

        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        

        // 添加乐观锁插件

        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        

        return interceptor;

    }

    

    // 配置元数据注入

    @Bean

    public IMetaObjectHandler metaObjectHandler() {

        return new MetaObjectHandler() {

            @Override

            public void insertFill(MetaObject metaObject) {

                this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());

                this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUsername());

            }

            

            @Override

            public void updateFill(MetaObject metaObject) {

                this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());

                this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUsername());

            }

        };

    }

}

```


### 应用配置


```yaml

mybatis-plus:

  configuration:

    map-underscore-to-camel-case: true

    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  global-config:

<"gssm.jiebaobifen.com">

<"ywop.jiebaobifen.com">

<"ohrr.jiebaobifen.com">

    db-config:

      id-type: auto

      logic-delete-field: deleted

      logic-delete-value: 1

      logic-not-delete-value: 0

```


## 实体类与Mapper设计


### 实体类定义


```java

@Data

@TableName("sys_user")

public class User {

    

    @TableId(type = IdType.AUTO)

    private Long id;

    

    private String username;

    

    private String email;

    

    private Integer age;

    

    @TableField(fill = FieldFill.INSERT)

    private LocalDateTime createTime;

    

    @TableField(fill = FieldFill.INSERT_UPDATE)

    private LocalDateTime updateTime;

    

    @Version

    private Integer version;

    

    @TableLogic

    private Integer deleted;

}


// 枚举类型处理

public enum UserStatus {

    ACTIVE(1, "激活"),

    INACTIVE(0, "未激活"),

    LOCKED(-1, "锁定");

    

    private final Integer code;

    private final String desc;

    

    UserStatus(Integer code, String desc) {

        this.code = code;

        this.desc = desc;

    }

    

    @Getter

    public static class StatusConverter implements AttributeConverter<UserStatus, Integer> {

        @Override

        public Integer convertToDatabaseColumn(UserStatus attribute) {

            return attribute != null ? attribute.getCode() : null;

        }

        

        @Override

        public UserStatus convertToEntityAttribute(Integer dbData) {

            return Arrays.stream(UserStatus.values())

                .filter(status -> status.getCode().equals(dbData))

                .findFirst()

                .orElse(null);

        }

    }

}

```


### Mapper接口定义


```java

public interface UserMapper extends BaseMapper<User> {

    

    // 自定义查询方法

    @Select("SELECT * FROM sys_user WHERE age > #{age}")

    List<User> selectUsersByAge(@Param("age") Integer age);

    

    // 复杂查询

    List<User> selectUsersWithConditions(@Param("username") String username, 

                                       @Param("minAge") Integer minAge,

                                       @Param("maxAge") Integer maxAge);

    

    // 分页查询

    Page<User> selectUserPage(Page<User> page, @Param("query") UserQuery query);

}


// 对应的XML映射

<!-- UserMapper.xml -->

<mapper namespace="com.example.mapper.UserMapper">

<"ccpg.jiebaobifen.com">

<"itka.jiebaobifen.com">

<"cqqd.jiebaobifen.com">

    <select id="selectUsersWithConditions" resultType="com.example.entity.User">

        SELECT * FROM sys_user 

        WHERE deleted = 0

        <if test="username != null and username != ''">

            AND username LIKE CONCAT('%', #{username}, '%')

        </if>

        <if test="minAge != null">

            AND age >= #{minAge}

        </if>

        <if test="maxAge != null">

            AND age <= #{maxAge}

        </if>

        ORDER BY create_time DESC

    </select>

</mapper>

```


## 核心功能实战


### 1. 条件构造器使用


```java

@Service

public class UserService {

    

    @Autowired

    private UserMapper userMapper;

    

    public List<User> findActiveUsers(String keyword, Integer minAge) {

        // 使用QueryWrapper构建查询条件

        QueryWrapper<User> wrapper = new QueryWrapper<>();

        wrapper.like(StringUtils.isNotBlank(keyword), "username", keyword)

               .ge(minAge != null, "age", minAge)

               .eq("deleted", 0)

               .orderByDesc("create_time");

        

        return userMapper.selectList(wrapper);

    }

    

    public Page<User> findUsersByPage(UserQuery query) {

        // 分页查询

        Page<User> page = new Page<>(query.getPageNum(), query.getPageSize());

        

        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();

        wrapper.like(StringUtils.isNotBlank(query.getUsername()), 

                    User::getUsername, query.getUsername())

               .between(query.getMinAge() != null && query.getMaxAge() != null,

                    User::getAge, query.getMinAge(), query.getMaxAge())

               .eq(User::getDeleted, 0);

        

        return userMapper.selectPage(page, wrapper);

    }

    

    public boolean updateUserEmail(Long userId, String newEmail) {

        // 使用UpdateWrapper进行更新

        UpdateWrapper<User> wrapper = new UpdateWrapper<>();

        wrapper.eq("id", userId)

               .set("email", newEmail)

               .set("update_time", LocalDateTime.now());

        

        return userMapper.update(null, wrapper) > 0;

    }

}

```


### 2. 事务管理


```java

@Service

@Transactional(rollbackFor = Exception.class)

<"ixyu.jiebaobifen.com">

<"alfv.jiebaobifen.com">

<"uvjo.jiebaobifen.com">

public class UserTransactionalService {

    

    @Autowired

    private UserMapper userMapper;

    

    @Autowired

    private UserLogMapper userLogMapper;

    

    public void createUserWithLog(User user) {

        // 插入用户

        userMapper.insert(user);

        

        // 记录日志

        UserLog userLog = new UserLog();

        userLog.setUserId(user.getId());

        userLog.setAction("CREATE");

        userLog.setCreateTime(LocalDateTime.now());

        userLogMapper.insert(userLog);

        

        // 如果这里出现异常,整个事务会回滚

        if (user.getAge() < 0) {

            throw new RuntimeException("年龄不能为负数");

        }

    }

    

    @Transactional(propagation = Propagation.REQUIRES_NEW)

    public void updateUserInNewTransaction(User user) {

        userMapper.updateById(user);

    }

}

```


### 3. 批量操作优化


```java

@Service

public class BatchOperationService {

    

    @Autowired

    private UserMapper userMapper;

    

    @Transactional(rollbackFor = Exception.class)

    public void batchInsertUsers(List<User> users) {

        // 使用Mybatis-Plus的批量插入

        users.forEach(user -> {

            user.setCreateTime(LocalDateTime.now());

            user.setUpdateTime(LocalDateTime.now());

        });

        

        // 批量插入,每批1000条

        int batchSize = 1000;

        for (int i = 0; i < users.size(); i += batchSize) {

            int end = Math.min(i + batchSize, users.size());

            List<User> batchList = users.subList(i, end);

            

            // 使用自定义的批量插入方法

            batchInsert(batchList);

        }

    }

    

    private void batchInsert(List<User> users) {

        SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH);

        try {

            UserMapper batchMapper = sqlSession.getMapper(UserMapper.class);

            for (User user : users) {

                batchMapper.insert(user);

            }

            sqlSession.commit();

        } finally {

            sqlSession.close();

        }

    }

    

    public void batchUpdateUsers(List<User> users) {

        // 使用UpdateWrapper进行批量更新

<"yard.jiebaobifen.com">

<"hziu.jiebaobifen.com">

<"glrw.jiebaobifen.com">

        users.forEach(user -> {

            UpdateWrapper<User> wrapper = new UpdateWrapper<>();

            wrapper.eq("id", user.getId())

                   .set("email", user.getEmail())

                   .set("update_time", LocalDateTime.now());

            userMapper.update(null, wrapper);

        });

    }

}

```


## 高级特性应用


### 1. 多租户数据隔离


```java

@Configuration

public class TenantConfig {

    

    @Bean

    public MybatisPlusInterceptor multiTenantInterceptor() {

        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        

        // 多租户插件

        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {

            @Override

            public Expression getTenantId() {

                // 从当前上下文中获取租户ID

                return new StringValue(getCurrentTenantId());

            }

            

            @Override

            public String getTenantIdColumn() {

                return "tenant_id";

            }

            

            @Override

            public boolean ignoreTable(String tableName) {

                // 忽略不需要租户隔离的表

                return "sys_tenant".equals(tableName);

            }

        }));

        

        return interceptor;

    }

    

    private String getCurrentTenantId() {

        // 从安全上下文中获取当前租户ID

        return SecurityUtils.getCurrentUserTenantId();

    }

}

```


### 2. 数据权限控制


```java

@Component

public class DataPermissionInterceptor implements InnerInterceptor {

    

    @Override

    public void beforeQuery(Executor executor, MappedStatement ms, 

                          Object parameter, RowBounds rowBounds, 

                          ResultHandler resultHandler, BoundSql boundSql) {

        

        // 解析SQL,添加数据权限过滤条件

        String originalSql = boundSql.getSql();

        String dataPermissionSql = addDataPermissionCondition(originalSql);

        

        // 使用反射修改BoundSql中的SQL

        ReflectUtil.setFieldValue(boundSql, "sql", dataPermissionSql);

    }

    

    private String addDataPermissionCondition(String sql) {

        // 根据当前用户权限添加数据过滤条件

        String userDeptCondition = getCurrentUserDeptCondition();

        if (StringUtils.isNotBlank(userDeptCondition)) {

            // 在WHERE条件中添加部门过滤

            return SqlParserUtil.addWhereCondition(sql, userDeptCondition);

        }

        return sql;

    }

    

    private String getCurrentUserDeptCondition() {

        User currentUser = SecurityUtils.getCurrentUser();

        if (currentUser != null && !currentUser.isAdmin()) {

            return "dept_id = '" + currentUser.getDeptId() + "'";

        }

        return null;

    }

}

```


## 性能优化实践


### 1. SQL执行监控


```java

@Slf4j

@Component

<"hgee.jiebaobifen.com">

<"xmun.jiebaobifen.com">

<"dkcn.jiebaobifen.com">

public class SqlLogInterceptor implements InnerInterceptor {

    

    @Override

    public void beforeQuery(Executor executor, MappedStatement ms, 

                          Object parameter, RowBounds rowBounds, 

                          ResultHandler resultHandler, BoundSql boundSql) {

        

        long startTime = System.currentTimeMillis();

        MDC.put("sqlStartTime", String.valueOf(startTime));

    }

    

    @Override

    public void afterQuery(Executor executor, MappedStatement ms, 

                         Object parameter, RowBounds rowBounds, 

                         ResultHandler resultHandler, BoundSql boundSql, 

                         List<Object> result) {

        

        long startTime = Long.parseLong(MDC.get("sqlStartTime"));

        long endTime = System.currentTimeMillis();

        long costTime = endTime - startTime;

        

        if (costTime > 1000) { // 超过1秒的SQL记录警告日志

            log.warn("慢SQL检测 - 执行时间: {}ms, SQL: {}", costTime, boundSql.getSql());

        }

        

        MDC.remove("sqlStartTime");

    }

}

```


### 2. 查询结果缓存


```java

@Service

@CacheConfig(cacheNames = "user")

public class UserCacheService {

    

    @Autowired

    private UserMapper userMapper;

    

    @Cacheable(key = "'user:' + #id")

    public User getUserById(Long id) {

        return userMapper.selectById(id);

    }

    

    @CacheEvict(key = "'user:' + #user.id")

    public void updateUser(User user) {

        userMapper.updateById(user);

    }

    

    @Caching(evict = {

        @CacheEvict(key = "'user:' + #id"),

        @CacheEvict(key = "'user:list'")

    })

    public void deleteUser(Long id) {

        userMapper.deleteById(id);

    }

}

```


## 最佳实践总结


### 1. 代码规范


- 实体类使用Lombok简化代码

- 字段命名遵循数据库规范(下划线命名)

- 为常用查询字段添加数据库索引


### 2. 性能优化


- 合理使用分页,避免一次性查询大量数据

- 批量操作使用批处理模式

- 复杂查询使用原生XML映射


### 3. 事务管理


- 明确的事务边界定义

- 合理的事务传播机制选择

- 异常处理与事务回滚策略


### 4. 安全考虑


- SQL注入防护(使用参数化查询)

- 数据权限控制

- 敏感数据脱敏处理


Mybatis-Plus通过丰富的功能和合理的抽象,显著提升了开发效率。遵循上述最佳实践,可以构建出既高效又维护性良好的数据访问层。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3102296/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933664