最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Mybatis-Plus 實戰(zhàn)使用與最佳實踐

 更新時間:2025年10月29日 09:36:40   作者:CodeSuc  
Mybatis作為優(yōu)秀的持久層框架,以其靈活性和可控性贏得了廣大開發(fā)者的青睞,本文將從實戰(zhàn)角度出發(fā),深入解析Mybatis-Plus的核心功能和最佳實踐,幫助開發(fā)者快速掌握這一強大的開發(fā)工具,感興趣的朋友跟隨小編一起看看吧

引言

在現(xiàn)代Java企業(yè)級開發(fā)中,數(shù)據(jù)持久層框架的選擇直接影響著開發(fā)效率和代碼質(zhì)量。Mybatis作為優(yōu)秀的持久層框架,以其靈活性和可控性贏得了廣大開發(fā)者的青睞。而Mybatis-Plus作為Mybatis的增強工具,在保持Mybatis原有特性的基礎(chǔ)上,提供了更加便捷的CRUD操作、強大的條件構(gòu)造器、代碼生成器等功能,極大地提升了開發(fā)效率。

本文將從實戰(zhàn)角度出發(fā),深入解析Mybatis-Plus的核心功能和最佳實踐,幫助開發(fā)者快速掌握這一強大的開發(fā)工具。我們將通過豐富的代碼示例和實際應(yīng)用場景,全面展示Mybatis-Plus在企業(yè)級項目中的應(yīng)用價值。

第一章:Mybatis-Plus概述與環(huán)境搭建

1.1 Mybatis-Plus簡介與核心特性

Mybatis-Plus(簡稱MP)是一個Mybatis的增強工具,在Mybatis的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生。它的設(shè)計理念是"只做增強不做改變",這意味著引入Mybatis-Plus不會對現(xiàn)有的Mybatis構(gòu)架產(chǎn)生任何影響。

1.1.1 核心特性概覽

Mybatis-Plus具有以下核心特性:

  • 無侵入:只做增強不做改變,引入它不會對現(xiàn)有工程產(chǎn)生影響
  • 損耗小:啟動即會自動注入基本CURD,性能基本無損耗,直接面向?qū)ο蟛僮?/li>
  • 強大的CRUD操作:內(nèi)置通用Mapper、通用Service,僅僅通過少量配置即可實現(xiàn)單表大部分CRUD操作
  • 支持Lambda形式調(diào)用:通過Lambda表達式,方便的編寫各類查詢條件,無需再擔(dān)心字段寫錯
  • 支持主鍵自動生成:支持多達4種主鍵策略,可自由配置,完美解決主鍵問題
  • 支持ActiveRecord模式:支持ActiveRecord形式調(diào)用,實體類只需繼承Model類即可進行強大的CRUD操作
  • 支持自定義全局通用操作:支持全局通用方法注入(Write once, use anywhere)
  • 內(nèi)置代碼生成器:采用代碼或者Maven插件可快速生成Mapper、Model、Service、Controller層代碼
  • 內(nèi)置分頁插件:基于Mybatis物理分頁,開發(fā)者無需關(guān)心具體操作,配置好插件之后,寫分頁等同于普通List查詢
  • 分頁插件支持多種數(shù)據(jù)庫:支持MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer等多種數(shù)據(jù)庫
  • 內(nèi)置性能分析插件:可輸出SQL語句以及其執(zhí)行時間,建議開發(fā)測試時啟用該功能,能快速揪出慢查詢
  • 內(nèi)置全局?jǐn)r截插件:提供全表delete、update操作智能分析阻斷,也可自定義攔截規(guī)則,預(yù)防誤操作

1.1.2 架構(gòu)設(shè)計理念

Mybatis-Plus的架構(gòu)設(shè)計遵循以下原則:

// 設(shè)計理念示例:只做增強不做改變
public interface UserMapper extends BaseMapper<User> {
    // 無需編寫任何代碼,即可獲得強大的CRUD功能
    // BaseMapper提供了豐富的CRUD方法
}
// 傳統(tǒng)Mybatis方式
public interface TraditionalUserMapper {
    int insert(User user);
    int deleteById(Long id);
    int updateById(User user);
    User selectById(Long id);
    List<User> selectList();
    // 需要編寫大量重復(fù)的CRUD方法
}

1.2 項目依賴配置與環(huán)境搭建

1.2.1 Maven依賴配置

在SpringBoot項目中集成Mybatis-Plus,首先需要添加相關(guān)依賴:

<!-- pom.xml -->
<dependencies>
    <!-- SpringBoot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- SpringBoot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Mybatis-Plus SpringBoot Starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3</version>
    </dependency>
    <!-- MySQL驅(qū)動 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- 連接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.16</version>
    </dependency>
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

1.2.2 Gradle依賴配置

對于使用Gradle的項目:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3'
    implementation 'mysql:mysql-connector-java'
    implementation 'com.alibaba:druid-spring-boot-starter:1.2.16'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

1.3 數(shù)據(jù)庫連接與基礎(chǔ)配置

1.3.1 application.yml配置

# application.yml
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456
    # Druid連接池配置
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
# Mybatis-Plus配置
mybatis-plus:
  configuration:
    # 開啟駝峰命名轉(zhuǎn)換
    map-underscore-to-camel-case: true
    # 開啟SQL日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 主鍵策略
      id-type: ASSIGN_ID
      # 邏輯刪除字段
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0
  # 掃描mapper文件
  mapper-locations: classpath*:/mapper/**/*.xml
  # 實體類別名包路徑
  type-aliases-package: com.example.entity

1.3.2 啟動類配置

@SpringBootApplication
@MapperScan("com.example.mapper")
public class MybatisPlusDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusDemoApplication.class, args);
    }
}

1.3.3 Mybatis-Plus配置類

@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {
    /**
     * 分頁插件配置
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分頁插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        paginationInnerInterceptor.setMaxLimit(1000L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        // 樂觀鎖插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
    /**
     * 自動填充配置
     */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MyMetaObjectHandler();
    }
}
/**
 * 自動填充處理器
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUser());
        this.strictInsertFill(metaObject, "updateBy", String.class, getCurrentUser());
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUser());
    }
    private String getCurrentUser() {
        // 這里可以從SecurityContext或其他地方獲取當(dāng)前用戶
        return "system";
    }
}

第二章:核心注解與基礎(chǔ)CRUD操作

2.1 實體類注解詳解

2.1.1 @TableName注解

@TableName注解用于指定實體類對應(yīng)的數(shù)據(jù)庫表名:

@Data
@TableName("sys_user")
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableLogic
    private Integer deleted;
}

2.1.2 @TableId注解詳解

@TableId注解用于標(biāo)識主鍵字段,支持多種主鍵生成策略:

public class IdTypeExample {
    // 自動增長主鍵
    @TableId(type = IdType.AUTO)
    private Long autoId;
    // 雪花算法ID(默認(rèn))
    @TableId(type = IdType.ASSIGN_ID)
    private Long snowflakeId;
    // UUID
    @TableId(type = IdType.ASSIGN_UUID)
    private String uuidId;
    // 手動輸入
    @TableId(type = IdType.INPUT)
    private Long inputId;
    // 無主鍵策略
    @TableId(type = IdType.NONE)
    private Long noneId;
}

2.1.3 @TableField注解應(yīng)用

@TableField注解用于配置字段的各種屬性:

@Data
@TableName("user_profile")
public class UserProfile {
    @TableId
    private Long id;
    // 指定數(shù)據(jù)庫字段名
    @TableField("user_name")
    private String username;
    // 字段不參與查詢
    @TableField(select = false)
    private String password;
    // 字段不存在于數(shù)據(jù)庫
    @TableField(exist = false)
    private String fullName;
    // 自動填充
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    // JSON字段處理
    @TableField(typeHandler = JacksonTypeHandler.class)
    private List<String> hobbies;
    // 條件策略
    @TableField(condition = SqlCondition.LIKE)
    private String description;
}

2.2 BaseMapper接口基礎(chǔ)操作

2.2.1 BaseMapper接口概述

BaseMapper接口提供了豐富的CRUD方法,無需編寫SQL即可完成常見的數(shù)據(jù)庫操作:

public interface UserMapper extends BaseMapper<User> {
    // 繼承BaseMapper后,自動獲得以下方法:
    // 插入操作:insert
    // 刪除操作:deleteById, deleteBatchIds, deleteByMap, delete
    // 更新操作:updateById, update
    // 查詢操作:selectById, selectBatchIds, selectByMap, selectOne, selectCount, selectList, selectMaps, selectObjs, selectPage, selectMapsPage
}

2.2.2 插入操作詳解

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 單條插入
     */
    public void insertUser() {
        User user = new User();
        user.setUsername("張三");
        user.setPassword("123456");
        user.setEmail("zhangsan@example.com");
        user.setAge(25);
        // 插入成功后,主鍵會自動回填到實體對象中
        int result = userMapper.insert(user);
        System.out.println("插入結(jié)果:" + result);
        System.out.println("生成的主鍵:" + user.getId());
    }
    /**
     * 批量插入(需要自定義實現(xiàn))
     */
    public void batchInsert(List<User> userList) {
        // Mybatis-Plus沒有提供批量插入的BaseMapper方法
        // 可以使用Service層的saveBatch方法
        // 或者自定義SQL實現(xiàn)真正的批量插入
        userList.forEach(user -> userMapper.insert(user));
    }
}

2.2.3 查詢操作詳解

@Service
public class UserQueryService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 根據(jù)ID查詢
     */
    public User selectById(Long id) {
        return userMapper.selectById(id);
    }
    /**
     * 根據(jù)ID批量查詢
     */
    public List<User> selectByIds(List<Long> ids) {
        return userMapper.selectBatchIds(ids);
    }
    /**
     * 根據(jù)Map條件查詢
     */
    public List<User> selectByMap() {
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("age", 25);
        columnMap.put("deleted", 0);
        return userMapper.selectByMap(columnMap);
    }
    /**
     * 查詢所有記錄
     */
    public List<User> selectAll() {
        return userMapper.selectList(null);
    }
    /**
     * 條件查詢
     */
    public List<User> selectByCondition() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("age", 25)
                   .like("username", "張")
                   .isNotNull("email")
                   .orderByDesc("create_time");
        return userMapper.selectList(queryWrapper);
    }
    /**
     * 統(tǒng)計查詢
     */
    public Long countUsers() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age", 18);
        return userMapper.selectCount(queryWrapper);
    }
}

2.2.4 更新操作詳解

@Service
public class UserUpdateService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 根據(jù)ID更新
     */
    public void updateById() {
        User user = new User();
        user.setId(1L);
        user.setUsername("李四");
        user.setAge(30);
        // 只更新非null字段
        userMapper.updateById(user);
    }
    /**
     * 條件更新
     */
    public void updateByCondition() {
        User user = new User();
        user.setAge(26);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("username", "張三")
                    .set("email", "zhangsan_new@example.com");
        userMapper.update(user, updateWrapper);
    }
    /**
     * 直接設(shè)置字段值更新
     */
    public void updateByWrapper() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("age", 25)
                    .set("age", 26)
                    .set("update_time", LocalDateTime.now());
        userMapper.update(null, updateWrapper);
    }
}

2.2.5 刪除操作詳解

@Service
public class UserDeleteService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 根據(jù)ID刪除
     */
    public void deleteById(Long id) {
        userMapper.deleteById(id);
    }
    /**
     * 批量刪除
     */
    public void deleteBatchIds(List<Long> ids) {
        userMapper.deleteBatchIds(ids);
    }
    /**
     * 根據(jù)Map條件刪除
     */
    public void deleteByMap() {
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("age", 0);
        columnMap.put("username", "test");
        userMapper.deleteByMap(columnMap);
    }
    /**
     * 條件刪除
     */
    public void deleteByCondition() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("age", 18)
                   .isNull("email");
        userMapper.delete(queryWrapper);
    }
}

2.3 Service層封裝與實戰(zhàn)應(yīng)用

2.3.1 IService接口介紹

Mybatis-Plus提供了IService接口,封裝了更多的CRUD操作:

public interface UserService extends IService<User> {
    // 繼承IService后,自動獲得豐富的CRUD方法
    // 如:save, saveBatch, saveOrUpdate, remove, update, get, list, page等
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    // ServiceImpl已經(jīng)實現(xiàn)了IService的所有方法
    // 可以直接使用,也可以重寫自定義實現(xiàn)
}

2.3.2 Service層常用方法

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    /**
     * 保存或更新
     */
    public void saveOrUpdateUser(User user) {
        // 根據(jù)主鍵判斷是插入還是更新
        this.saveOrUpdate(user);
    }
    /**
     * 批量保存
     */
    public void batchSave(List<User> userList) {
        // 批量插入,默認(rèn)批次大小為1000
        this.saveBatch(userList);
        // 自定義批次大小
        this.saveBatch(userList, 500);
    }
    /**
     * 條件查詢
     */
    public List<User> getActiveUsers() {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getDeleted, 0)
                   .gt(User::getAge, 18)
                   .orderByDesc(User::getCreateTime);
        return this.list(queryWrapper);
    }
    /**
     * 分頁查詢
     */
    public IPage<User> getUserPage(int current, int size, String keyword) {
        Page<User> page = new Page<>(current, size);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.like(User::getUsername, keyword)
                       .or()
                       .like(User::getEmail, keyword);
        }
        queryWrapper.eq(User::getDeleted, 0)
                   .orderByDesc(User::getCreateTime);
        return this.page(page, queryWrapper);
    }
    /**
     * 統(tǒng)計查詢
     */
    public long countActiveUsers() {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getDeleted, 0)
                   .gt(User::getAge, 18);
        return this.count(queryWrapper);
    }
}

第三章:條件構(gòu)造器與復(fù)雜查詢

3.1 QueryWrapper查詢條件構(gòu)造

3.1.1 基礎(chǔ)條件構(gòu)造

QueryWrapper是Mybatis-Plus提供的查詢條件構(gòu)造器,支持鏈?zhǔn)秸{(diào)用:

@Service
public class QueryWrapperService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 基礎(chǔ)條件查詢
     */
    public List<User> basicQuery() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 等值查詢
        queryWrapper.eq("age", 25);
        // 不等值查詢
        queryWrapper.ne("username", "admin");
        // 大于、小于查詢
        queryWrapper.gt("age", 18)
                   .lt("age", 60);
        // 大于等于、小于等于
        queryWrapper.ge("create_time", "2023-01-01")
                   .le("create_time", "2023-12-31");
        // 模糊查詢
        queryWrapper.like("username", "張")
                   .likeLeft("email", "@qq.com")  // %@qq.com
                   .likeRight("username", "admin"); // admin%
        // 空值查詢
        queryWrapper.isNull("deleted_time")
                   .isNotNull("email");
        // 范圍查詢
        queryWrapper.in("age", Arrays.asList(20, 25, 30))
                   .notIn("status", Arrays.asList(0, -1));
        // 區(qū)間查詢
        queryWrapper.between("age", 20, 30)
                   .notBetween("create_time", "2023-01-01", "2023-06-01");
        return userMapper.selectList(queryWrapper);
    }
    /**
     * 復(fù)雜條件組合
     */
    public List<User> complexQuery() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // (age > 18 AND age < 60) AND (username LIKE '%admin%' OR email IS NOT NULL)
        queryWrapper.gt("age", 18)
                   .lt("age", 60)
                   .and(wrapper -> wrapper.like("username", "admin")
                                         .or()
                                         .isNotNull("email"));
        // 嵌套查詢
        queryWrapper.nested(wrapper -> wrapper.eq("status", 1)
                                             .or()
                                             .eq("status", 2));
        return userMapper.selectList(queryWrapper);
    }
    /**
     * 動態(tài)條件查詢
     */
    public List<User> dynamicQuery(String username, Integer minAge, Integer maxAge, String email) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 條件動態(tài)拼接
        queryWrapper.like(StringUtils.isNotBlank(username), "username", username)
                   .ge(minAge != null, "age", minAge)
                   .le(maxAge != null, "age", maxAge)
                   .eq(StringUtils.isNotBlank(email), "email", email);
        return userMapper.selectList(queryWrapper);
    }
}

3.1.2 排序與分組

@Service
public class QueryOrderService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 排序查詢
     */
    public List<User> orderQuery() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 單字段排序
        queryWrapper.orderByAsc("age")
                   .orderByDesc("create_time");
        // 多字段排序
        queryWrapper.orderBy(true, true, "age", "username")
                   .orderBy(true, false, "create_time");
        return userMapper.selectList(queryWrapper);
    }
    /**
     * 分組查詢
     */
    public List<Map<String, Object>> groupQuery() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("age", "count(*) as count")
                   .groupBy("age")
                   .having("count(*) > 1")
                   .orderByDesc("count");
        return userMapper.selectMaps(queryWrapper);
    }
    /**
     * 字段選擇查詢
     */
    public List<User> selectFields() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 選擇特定字段
        queryWrapper.select("id", "username", "email", "age")
                   .eq("deleted", 0);
        return userMapper.selectList(queryWrapper);
    }
    /**
     * 排除字段查詢
     */
    public List<User> excludeFields() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 排除敏感字段
        queryWrapper.select(User.class, info -> !info.getColumn().equals("password"))
                   .eq("deleted", 0);
        return userMapper.selectList(queryWrapper);
    }
}

3.2 UpdateWrapper更新條件構(gòu)造

3.2.1 基礎(chǔ)更新操作

@Service
public class UpdateWrapperService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 條件更新
     */
    public void updateByCondition() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        // 設(shè)置更新字段
        updateWrapper.set("age", 26)
                    .set("update_time", LocalDateTime.now())
                    .eq("username", "張三")
                    .eq("deleted", 0);
        userMapper.update(null, updateWrapper);
    }
    /**
     * 字段自增更新
     */
    public void incrementUpdate() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        // 年齡自增1
        updateWrapper.setSql("age = age + 1")
                    .eq("id", 1L);
        userMapper.update(null, updateWrapper);
    }
    /**
     * 批量條件更新
     */
    public void batchUpdate() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("status", 1)
                    .set("update_time", LocalDateTime.now())
                    .in("id", Arrays.asList(1L, 2L, 3L))
                    .eq("deleted", 0);
        userMapper.update(null, updateWrapper);
    }
    /**
     * 復(fù)雜條件更新
     */
    public void complexUpdate() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("status", 2)
                    .set("remark", "批量更新")
                    .gt("age", 18)
                    .lt("age", 60)
                    .and(wrapper -> wrapper.like("username", "test")
                                          .or()
                                          .isNull("email"));
        userMapper.update(null, updateWrapper);
    }
}

3.3 Lambda表達式條件構(gòu)造器

3.3.1 LambdaQueryWrapper使用

Lambda表達式條件構(gòu)造器提供了類型安全的字段引用,避免了字符串硬編碼:

@Service
public class LambdaQueryService {
    @Autowired
    private UserMapper userMapper;
    /**
     * Lambda查詢基礎(chǔ)用法
     */
    public List<User> lambdaQuery() {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        // 類型安全的字段引用
        queryWrapper.eq(User::getAge, 25)
                   .like(User::getUsername, "張")
                   .isNotNull(User::getEmail)
                   .orderByDesc(User::getCreateTime);
        return userMapper.selectList(queryWrapper);
    }
    /**
     * 動態(tài)Lambda查詢
     */
    public List<User> dynamicLambdaQuery(UserQueryDTO queryDTO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(queryDTO.getUsername()), 
                         User::getUsername, queryDTO.getUsername())
                   .eq(queryDTO.getAge() != null, 
                      User::getAge, queryDTO.getAge())
                   .ge(queryDTO.getMinAge() != null, 
                      User::getAge, queryDTO.getMinAge())
                   .le(queryDTO.getMaxAge() != null, 
                      User::getAge, queryDTO.getMaxAge())
                   .eq(StringUtils.isNotBlank(queryDTO.getEmail()), 
                      User::getEmail, queryDTO.getEmail())
                   .eq(User::getDeleted, 0)
                   .orderByDesc(User::getCreateTime);
        return userMapper.selectList(queryWrapper);
    }
    /**
     * Lambda分頁查詢
     */
    public IPage<User> lambdaPageQuery(int current, int size, UserQueryDTO queryDTO) {
        Page<User> page = new Page<>(current, size);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        // 構(gòu)建查詢條件
        queryWrapper.like(StringUtils.isNotBlank(queryDTO.getUsername()), 
                         User::getUsername, queryDTO.getUsername())
                   .eq(queryDTO.getStatus() != null, 
                      User::getStatus, queryDTO.getStatus())
                   .between(queryDTO.getStartTime() != null && queryDTO.getEndTime() != null,
                           User::getCreateTime, queryDTO.getStartTime(), queryDTO.getEndTime())
                   .eq(User::getDeleted, 0);
        // 排序
        if (StringUtils.isNotBlank(queryDTO.getOrderBy())) {
            if ("age".equals(queryDTO.getOrderBy())) {
                queryWrapper.orderBy(true, queryDTO.isAsc(), User::getAge);
            } else if ("createTime".equals(queryDTO.getOrderBy())) {
                queryWrapper.orderBy(true, queryDTO.isAsc(), User::getCreateTime);
            }
        } else {
            queryWrapper.orderByDesc(User::getCreateTime);
        }
        return userMapper.selectPage(page, queryWrapper);
    }
}
/**
 * 查詢DTO
 */
@Data
public class UserQueryDTO {
    private String username;
    private Integer age;
    private Integer minAge;
    private Integer maxAge;
    private String email;
    private Integer status;
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private String orderBy;
    private boolean asc = false;
}

3.3.2 LambdaUpdateWrapper使用

@Service
public class LambdaUpdateService {
    @Autowired
    private UserMapper userMapper;
    /**
     * Lambda更新操作
     */
    public void lambdaUpdate() {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getAge, 26)
                    .set(User::getUpdateTime, LocalDateTime.now())
                    .eq(User::getUsername, "張三")
                    .eq(User::getDeleted, 0);
        userMapper.update(null, updateWrapper);
    }
    /**
     * 條件Lambda更新
     */
    public void conditionalLambdaUpdate(Long userId, UserUpdateDTO updateDTO) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        // 動態(tài)設(shè)置更新字段
        updateWrapper.set(StringUtils.isNotBlank(updateDTO.getUsername()), 
                         User::getUsername, updateDTO.getUsername())
                    .set(updateDTO.getAge() != null, 
                         User::getAge, updateDTO.getAge())
                    .set(StringUtils.isNotBlank(updateDTO.getEmail()), 
                         User::getEmail, updateDTO.getEmail())
                    .set(User::getUpdateTime, LocalDateTime.now())
                    .eq(User::getId, userId)
                    .eq(User::getDeleted, 0);
        userMapper.update(null, updateWrapper);
    }
}
/**
 * 更新DTO
 */
@Data
public class UserUpdateDTO {
    private String username;
    private Integer age;
    private String email;
    private Integer status;
}

第四章:代碼生成器與自動化開發(fā)

4.1 代碼生成器配置與使用

4.1.1 代碼生成器依賴

首先需要添加代碼生成器相關(guān)依賴:

<!-- 代碼生成器 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

4.1.2 基礎(chǔ)代碼生成器配置

public class CodeGenerator {
    public static void main(String[] args) {
        // 代碼生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("your-name");
        gc.setOpen(false);
        gc.setFileOverride(true);
        gc.setServiceName("%sService");
        gc.setIdType(IdType.ASSIGN_ID);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);
        // 數(shù)據(jù)源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("system");
        pc.setParent("com.example");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setController("controller");
        mpg.setPackageInfo(pc);
        // 自定義配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                map.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                this.setMap(map);
            }
        };
        // 自定義輸出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定義配置會被優(yōu)先輸出
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude("sys_user", "sys_role", "sys_permission");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        strategy.setLogicDeleteFieldName("deleted");
        strategy.setVersionFieldName("version");
        strategy.setEntityTableFieldAnnotationEnable(true);
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new VelocityTemplateEngine());
        mpg.execute();
    }
}

4.1.3 高級代碼生成器配置

@Component
public class AdvancedCodeGenerator {
    /**
     * 交互式代碼生成器
     */
    public void interactiveGenerate() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("請輸入表名(多個表名用逗號分隔):");
        String tableNames = scanner.nextLine();
        System.out.println("請輸入模塊名:");
        String moduleName = scanner.nextLine();
        System.out.println("請輸入作者名:");
        String author = scanner.nextLine();
        generateCode(tableNames, moduleName, author);
    }
    /**
     * 代碼生成核心方法
     */
    private void generateCode(String tableNames, String moduleName, String author) {
        // 代碼生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = buildGlobalConfig(author);
        mpg.setGlobalConfig(gc);
        // 數(shù)據(jù)源配置
        DataSourceConfig dsc = buildDataSourceConfig();
        mpg.setDataSource(dsc);
        // 包配置
        PackageConfig pc = buildPackageConfig(moduleName);
        mpg.setPackageInfo(pc);
        // 自定義配置
        InjectionConfig cfg = buildInjectionConfig(pc);
        mpg.setCfg(cfg);
        // 配置模板
        TemplateConfig templateConfig = buildTemplateConfig();
        mpg.setTemplate(templateConfig);
        // 策略配置
        StrategyConfig strategy = buildStrategyConfig(tableNames, pc);
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new VelocityTemplateEngine());
        mpg.execute();
    }
    private GlobalConfig buildGlobalConfig(String author) {
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor(author);
        gc.setOpen(false);
        gc.setFileOverride(true);
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setControllerName("%sController");
        gc.setIdType(IdType.ASSIGN_ID);
        gc.setDateType(DateType.TIME_PACK);
        gc.setSwagger2(true);
        gc.setActiveRecord(false);
        gc.setEnableCache(false);
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        return gc;
    }
    private DataSourceConfig buildDataSourceConfig() {
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        return dsc;
    }
    private PackageConfig buildPackageConfig(String moduleName) {
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(moduleName);
        pc.setParent("com.example");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setController("controller");
        return pc;
    }
    private InjectionConfig buildInjectionConfig(PackageConfig pc) {
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                map.put("date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                map.put("author", "Code Generator");
                this.setMap(map);
            }
        };
        // 自定義輸出配置
        List<FileOutConfig> focList = new ArrayList<>();
        String projectPath = System.getProperty("user.dir");
        // 自定義Mapper XML輸出
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        // 自定義DTO輸出
        focList.add(new FileOutConfig("/templates/dto.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/com/example/" + pc.getModuleName() 
                        + "/dto/" + tableInfo.getEntityName() + "DTO" + StringPool.DOT_JAVA;
            }
        });
        // 自定義VO輸出
        focList.add(new FileOutConfig("/templates/vo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/com/example/" + pc.getModuleName() 
                        + "/vo/" + tableInfo.getEntityName() + "VO" + StringPool.DOT_JAVA;
            }
        });
        cfg.setFileOutConfigList(focList);
        return cfg;
    }
    private TemplateConfig buildTemplateConfig() {
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);
        return templateConfig;
    }
    private StrategyConfig buildStrategyConfig(String tableNames, PackageConfig pc) {
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude(tableNames.split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        strategy.setLogicDeleteFieldName("deleted");
        strategy.setVersionFieldName("version");
        strategy.setEntityTableFieldAnnotationEnable(true);
        // 字段填充策略
        List<TableFill> tableFillList = new ArrayList<>();
        tableFillList.add(new TableFill("create_time", FieldFill.INSERT));
        tableFillList.add(new TableFill("update_time", FieldFill.INSERT_UPDATE));
        tableFillList.add(new TableFill("create_by", FieldFill.INSERT));
        tableFillList.add(new TableFill("update_by", FieldFill.INSERT_UPDATE));
        strategy.setTableFillList(tableFillList);
        return strategy;
    }
}

4.2 自定義模板與代碼規(guī)范

4.2.1 自定義Entity模板

創(chuàng)建自定義Entity模板 /templates/entity.java.vm

package ${package.Entity};
#foreach($pkg in ${table.importPackages})
import ${pkg};
#end
#if(${swagger2})
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#end
#if(${entityLombokModel})
import lombok.Data;
import lombok.EqualsAndHashCode;
#end
/**
 * ${table.comment!} 實體類
 *
 * @author ${author}
 * @since ${date}
 */
#if(${entityLombokModel})
@Data
#if(${superEntityClass})
@EqualsAndHashCode(callSuper = true)
#else
@EqualsAndHashCode(callSuper = false)
#end
#end
#if(${table.convert})
@TableName("${table.name}")
#end
#if(${swagger2})
@ApiModel(value = "${entity}對象", description = "${table.comment!}")
#end
#if(${superEntityClass})
public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
#elseif(${activeRecord})
public class ${entity} extends Model<${entity}> {
#else
public class ${entity} implements Serializable {
#end
    private static final long serialVersionUID = 1L;
#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if("$!field.comment" != "")
    /**
     * ${field.comment}
     */
#end
#if(${field.keyFlag})
#if(${field.keyIdentityFlag})
    @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
#elseif(!$null.isNull(${idType}) && "$!idType" != "")
    @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
#elseif(${field.convert})
    @TableId("${field.annotationColumnName}")
#end
#elseif(${field.fill})
#if(${field.convert})
    @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
#else
    @TableField(fill = FieldFill.${field.fill})
#end
#elseif(${field.convert})
    @TableField("${field.annotationColumnName}")
#end
#if("${field.propertyType}" == "Integer")
    @ApiModelProperty(value = "${field.comment}")
    private ${field.propertyType} ${field.propertyName};
#else
    @ApiModelProperty(value = "${field.comment}")
    private ${field.propertyType} ${field.propertyName};
#end
#end
#if(!${entityLombokModel})
#foreach($field in ${table.fields})
#if(${field.propertyType.equals("boolean")})
#set($getprefix="is")
#else
#set($getprefix="get")
#end
    public ${field.propertyType} ${getprefix}${field.capitalName}() {
        return ${field.propertyName};
    }
    public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
        this.${field.propertyName} = ${field.propertyName};
    }
#end
#end
#if(${activeRecord})
    @Override
    protected Serializable pkVal() {
#if(${keyPropertyName})
        return this.${keyPropertyName};
#else
        return null;
#end
    }
#end
#if(!${entityLombokModel})
    @Override
    public String toString() {
        return "${entity}{" +
#foreach($field in ${table.fields})
#if($!{foreach.index}==0)
        "${field.propertyName}=" + ${field.propertyName} +
#else
        ", ${field.propertyName}=" + ${field.propertyName} +
#end
#end
        "}";
    }
#end
}

4.2.2 自定義Controller模板

創(chuàng)建自定義Controller模板 /templates/controller.java.vm

package ${package.Controller};
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};
#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
/**
 * ${table.comment!} 前端控制器
 *
 * @author ${author}
 * @since ${date}
 */
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
@Api(tags = "${table.comment!}管理")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
#else
#if(${superControllerClass})
public class ${table.controllerName} extends ${superControllerClass} {
#else
public class ${table.controllerName} {
#end
    @Autowired
    private ${table.serviceName} ${table.entityPath}Service;
    /**
     * 分頁查詢
     */
    @GetMapping("/page")
    @ApiOperation("分頁查詢${table.comment!}")
    public Result<Page<${entity}>> page(@ApiParam("當(dāng)前頁") @RequestParam(defaultValue = "1") Integer current,
                                        @ApiParam("頁大小") @RequestParam(defaultValue = "10") Integer size) {
        Page<${entity}> page = new Page<>(current, size);
        return Result.success(${table.entityPath}Service.page(page));
    }
    /**
     * 根據(jù)ID查詢
     */
    @GetMapping("/{id}")
    @ApiOperation("根據(jù)ID查詢${table.comment!}")
    public Result<${entity}> getById(@ApiParam("主鍵ID") @PathVariable Long id) {
        return Result.success(${table.entityPath}Service.getById(id));
    }
    /**
     * 新增
     */
    @PostMapping
    @ApiOperation("新增${table.comment!}")
    public Result<Boolean> save(@RequestBody ${entity} ${table.entityPath}) {
        return Result.success(${table.entityPath}Service.save(${table.entityPath}));
    }
    /**
     * 修改
     */
    @PutMapping
    @ApiOperation("修改${table.comment!}")
    public Result<Boolean> updateById(@RequestBody ${entity} ${table.entityPath}) {
        return Result.success(${table.entityPath}Service.updateById(${table.entityPath}));
    }
    /**
     * 刪除
     */
    @DeleteMapping("/{id}")
    @ApiOperation("刪除${table.comment!}")
    public Result<Boolean> removeById(@ApiParam("主鍵ID") @PathVariable Long id) {
        return Result.success(${table.entityPath}Service.removeById(id));
    }
}
#end

4.3 批量生成與項目集成

4.3.1 批量生成工具類

@Component
public class BatchCodeGenerator {
    /**
     * 批量生成指定數(shù)據(jù)庫的所有表
     */
    public void generateAllTables(String databaseName) {
        List<String> tableNames = getAllTableNames(databaseName);
        for (String tableName : tableNames) {
            generateSingleTable(tableName, getModuleNameFromTable(tableName));
        }
    }
    /**
     * 根據(jù)配置文件批量生成
     */
    public void generateByConfig(String configPath) {
        try {
            Properties config = new Properties();
            config.load(new FileInputStream(configPath));
            String tables = config.getProperty("tables");
            String moduleName = config.getProperty("moduleName");
            String author = config.getProperty("author");
            String packageName = config.getProperty("packageName");
            generateCodeWithConfig(tables, moduleName, author, packageName);
        } catch (IOException e) {
            throw new RuntimeException("讀取配置文件失敗", e);
        }
    }
    /**
     * 獲取數(shù)據(jù)庫所有表名
     */
    private List<String> getAllTableNames(String databaseName) {
        List<String> tableNames = new ArrayList<>();
        String sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = ?";
        try (Connection connection = getConnection();
             PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setString(1, databaseName);
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                tableNames.add(resultSet.getString("table_name"));
            }
        } catch (SQLException e) {
            throw new RuntimeException("獲取表名失敗", e);
        }
        return tableNames;
    }
    /**
     * 根據(jù)表名推斷模塊名
     */
    private String getModuleNameFromTable(String tableName) {
        if (tableName.startsWith("sys_")) {
            return "system";
        } else if (tableName.startsWith("user_")) {
            return "user";
        } else if (tableName.startsWith("order_")) {
            return "order";
        } else {
            return "common";
        }
    }
    /**
     * 獲取數(shù)據(jù)庫連接
     */
    private Connection getConnection() throws SQLException {
        String url = "jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "123456";
        return DriverManager.getConnection(url, username, password);
    }
    /**
     * 單表生成
     */
    private void generateSingleTable(String tableName, String moduleName) {
        AutoGenerator mpg = new AutoGenerator();
        // 配置生成器
        configureGenerator(mpg, tableName, moduleName);
        // 執(zhí)行生成
        mpg.execute();
        System.out.println("表 " + tableName + " 代碼生成完成!");
    }
    /**
     * 配置生成器
     */
    private void configureGenerator(AutoGenerator mpg, String tableName, String moduleName) {
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("Mybatis-Plus Generator");
        gc.setOpen(false);
        gc.setFileOverride(true);
        gc.setServiceName("%sService");
        gc.setIdType(IdType.ASSIGN_ID);
        gc.setDateType(DateType.TIME_PACK);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);
        // 數(shù)據(jù)源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(moduleName);
        pc.setParent("com.example");
        mpg.setPackageInfo(pc);
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude(tableName);
        strategy.setLogicDeleteFieldName("deleted");
        strategy.setEntityTableFieldAnnotationEnable(true);
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new VelocityTemplateEngine());
    }
}

4.3.2 Maven插件集成

在pom.xml中配置Mybatis-Plus代碼生成器插件:

<build>
    <plugins>
        <!-- Mybatis-Plus代碼生成器插件 -->
        <plugin>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-maven-plugin</artifactId>
            <version>1.0.0</version>
            <configuration>
                <configurationFile>src/main/resources/generator-config.xml</configurationFile>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.33</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

4.3.3 配置文件管理

創(chuàng)建生成器配置文件 generator.properties

# 數(shù)據(jù)庫配置
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=123456
# 生成配置
generator.author=Mybatis-Plus Generator
generator.packageName=com.example
generator.moduleName=system
generator.tables=sys_user,sys_role,sys_permission
# 輸出配置
generator.outputDir=/src/main/java
generator.mapperXmlDir=/src/main/resources/mapper
# 策略配置
generator.tablePrefix=sys_
generator.logicDeleteField=deleted
generator.versionField=version
generator.enableLombok=true
generator.enableSwagger=true
generator.enableRestController=true

第五章:高級特性與性能優(yōu)化

5.1 分頁插件與性能優(yōu)化

5.1.1 分頁插件配置

Mybatis-Plus提供了強大的分頁插件,支持多種數(shù)據(jù)庫:

@Configuration
public class MybatisPlusPageConfig {
    /**
     * 分頁插件配置
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分頁插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 設(shè)置數(shù)據(jù)庫類型
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        // 設(shè)置最大單頁限制數(shù)量,默認(rèn)500條,-1不受限制
        paginationInnerInterceptor.setMaxLimit(1000L);
        // 溢出總頁數(shù)后是否進行處理
        paginationInnerInterceptor.setOverflow(false);
        // 生成countSql優(yōu)化掉join現(xiàn)象
        paginationInnerInterceptor.setOptimizeJoin(true);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

5.1.2 分頁查詢實戰(zhàn)

@Service
public class UserPageService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 基礎(chǔ)分頁查詢
     */
    public IPage<User> basicPage(int current, int size) {
        Page<User> page = new Page<>(current, size);
        return userMapper.selectPage(page, null);
    }
    /**
     * 條件分頁查詢
     */
    public IPage<User> conditionalPage(UserPageQuery query) {
        Page<User> page = new Page<>(query.getCurrent(), query.getSize());
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(query.getUsername()), 
                         User::getUsername, query.getUsername())
                   .eq(query.getStatus() != null, 
                      User::getStatus, query.getStatus())
                   .between(query.getStartTime() != null && query.getEndTime() != null,
                           User::getCreateTime, query.getStartTime(), query.getEndTime())
                   .eq(User::getDeleted, 0)
                   .orderByDesc(User::getCreateTime);
        return userMapper.selectPage(page, queryWrapper);
    }
    /**
     * 自定義分頁查詢
     */
    public IPage<UserVO> customPage(UserPageQuery query) {
        Page<UserVO> page = new Page<>(query.getCurrent(), query.getSize());
        return userMapper.selectUserPage(page, query);
    }
    /**
     * 不查詢總數(shù)的分頁
     */
    public IPage<User> pageWithoutCount(int current, int size) {
        Page<User> page = new Page<>(current, size, false);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getDeleted, 0)
                   .orderByDesc(User::getCreateTime);
        return userMapper.selectPage(page, queryWrapper);
    }
}
/**
 * 分頁查詢參數(shù)
 */
@Data
public class UserPageQuery {
    private Integer current = 1;
    private Integer size = 10;
    private String username;
    private Integer status;
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private String orderBy;
    private Boolean asc = false;
}
/**
 * 用戶視圖對象
 */
@Data
public class UserVO {
    private Long id;
    private String username;
    private String email;
    private Integer age;
    private String roleName;
    private LocalDateTime createTime;
}

5.1.3 自定義分頁查詢

在Mapper中定義自定義分頁查詢:

public interface UserMapper extends BaseMapper<User> {
    /**
     * 自定義分頁查詢
     */
    IPage<UserVO> selectUserPage(Page<UserVO> page, @Param("query") UserPageQuery query);
    /**
     * 復(fù)雜統(tǒng)計分頁查詢
     */
    IPage<UserStatVO> selectUserStatPage(Page<UserStatVO> page, @Param("query") UserStatQuery query);
}

對應(yīng)的XML映射:

<!-- UserMapper.xml -->
<select id="selectUserPage" resultType="com.example.vo.UserVO">
    SELECT 
        u.id,
        u.username,
        u.email,
        u.age,
        r.role_name,
        u.create_time
    FROM sys_user u
    LEFT JOIN sys_user_role ur ON u.id = ur.user_id
    LEFT JOIN sys_role r ON ur.role_id = r.id
    WHERE u.deleted = 0
    <if test="query.username != null and query.username != ''">
        AND u.username LIKE CONCAT('%', #{query.username}, '%')
    </if>
    <if test="query.status != null">
        AND u.status = #{query.status}
    </if>
    <if test="query.startTime != null and query.endTime != null">
        AND u.create_time BETWEEN #{query.startTime} AND #{query.endTime}
    </if>
    ORDER BY u.create_time DESC
</select>
<select id="selectUserStatPage" resultType="com.example.vo.UserStatVO">
    SELECT 
        DATE_FORMAT(u.create_time, '%Y-%m') as month,
        COUNT(*) as userCount,
        COUNT(CASE WHEN u.status = 1 THEN 1 END) as activeCount,
        AVG(u.age) as avgAge
    FROM sys_user u
    WHERE u.deleted = 0
    <if test="query.startTime != null and query.endTime != null">
        AND u.create_time BETWEEN #{query.startTime} AND #{query.endTime}
    </if>
    GROUP BY DATE_FORMAT(u.create_time, '%Y-%m')
    ORDER BY month DESC
</select>

5.2 邏輯刪除與數(shù)據(jù)安全

5.2.1 邏輯刪除配置

@Configuration
public class LogicDeleteConfig {
    /**
     * 邏輯刪除配置
     */
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
}

在實體類中配置邏輯刪除字段:

@Data
@TableName("sys_user")
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    /**
     * 邏輯刪除字段
     * 0-未刪除,1-已刪除
     */
    @TableLogic
    @TableField(value = "deleted", fill = FieldFill.INSERT)
    private Integer deleted;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

5.2.2 邏輯刪除實戰(zhàn)應(yīng)用

@Service
public class LogicDeleteService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 邏輯刪除單個用戶
     */
    public boolean logicDeleteUser(Long userId) {
        // 調(diào)用deleteById會自動進行邏輯刪除
        return userMapper.deleteById(userId) > 0;
    }
    /**
     * 批量邏輯刪除
     */
    public boolean batchLogicDelete(List<Long> userIds) {
        return userMapper.deleteBatchIds(userIds) > 0;
    }
    /**
     * 條件邏輯刪除
     */
    public boolean logicDeleteByCondition(Integer status) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getStatus, status)
                    .set(User::getDeleted, 1)
                    .set(User::getUpdateTime, LocalDateTime.now());
        return userMapper.update(null, updateWrapper) > 0;
    }
    /**
     * 查詢包含已刪除的數(shù)據(jù)
     */
    public List<User> selectWithDeleted() {
        // 使用原生SQL查詢,繞過邏輯刪除
        return userMapper.selectList(new QueryWrapper<User>().last("/* 包含已刪除數(shù)據(jù) */"));
    }
    /**
     * 恢復(fù)邏輯刪除的數(shù)據(jù)
     */
    public boolean restoreUser(Long userId) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, userId)
                    .set(User::getDeleted, 0)
                    .set(User::getUpdateTime, LocalDateTime.now());
        return userMapper.update(null, updateWrapper) > 0;
    }
    /**
     * 物理刪除(真正刪除數(shù)據(jù))
     */
    public boolean physicalDelete(Long userId) {
        // 需要自定義SQL實現(xiàn)物理刪除
        return userMapper.physicalDeleteById(userId) > 0;
    }
}

在Mapper中添加物理刪除方法:

public interface UserMapper extends BaseMapper<User> {
    /**
     * 物理刪除用戶
     */
    @Delete("DELETE FROM sys_user WHERE id = #{userId}")
    int physicalDeleteById(@Param("userId") Long userId);
    /**
     * 查詢包含已刪除的用戶
     */
    @Select("SELECT * FROM sys_user WHERE id = #{userId}")
    User selectByIdWithDeleted(@Param("userId") Long userId);
}

5.3 自動填充與審計功能

5.3.1 自動填充配置

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    private static final Logger log = LoggerFactory.getLogger(MyMetaObjectHandler.class);
    /**
     * 插入時自動填充
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("開始插入填充...");
        // 填充創(chuàng)建時間
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        // 填充更新時間
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        // 填充創(chuàng)建人
        this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUserId());
        // 填充更新人
        this.strictInsertFill(metaObject, "updateBy", String.class, getCurrentUserId());
        // 填充邏輯刪除字段
        this.strictInsertFill(metaObject, "deleted", Integer.class, 0);
        // 填充版本號
        this.strictInsertFill(metaObject, "version", Integer.class, 1);
    }
    /**
     * 更新時自動填充
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("開始更新填充...");
        // 填充更新時間
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        // 填充更新人
        this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUserId());
    }
    /**
     * 獲取當(dāng)前用戶ID
     */
    private String getCurrentUserId() {
        // 從Spring Security上下文獲取當(dāng)前用戶
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated()) {
                Object principal = authentication.getPrincipal();
                if (principal instanceof UserDetails) {
                    return ((UserDetails) principal).getUsername();
                } else {
                    return principal.toString();
                }
            }
        } catch (Exception e) {
            log.warn("獲取當(dāng)前用戶失敗", e);
        }
        // 從請求頭獲取用戶信息
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            String userId = request.getHeader("X-User-Id");
            if (StringUtils.isNotBlank(userId)) {
                return userId;
            }
        } catch (Exception e) {
            log.warn("從請求頭獲取用戶ID失敗", e);
        }
        return "system";
    }
}

5.3.2 審計實體基類

@Data
@MappedSuperclass
public abstract class BaseAuditEntity {
    /**
     * 創(chuàng)建時間
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * 更新時間
     */
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    /**
     * 創(chuàng)建人
     */
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;
    /**
     * 更新人
     */
    @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
    private String updateBy;
    /**
     * 邏輯刪除
     */
    @TableLogic
    @TableField(value = "deleted", fill = FieldFill.INSERT)
    private Integer deleted;
    /**
     * 版本號(樂觀鎖)
     */
    @Version
    @TableField(value = "version", fill = FieldFill.INSERT)
    private Integer version;
}

繼承審計基類的實體:

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user")
public class User extends BaseAuditEntity {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    private Integer status;
}

5.3.3 樂觀鎖配置與使用

@Configuration
public class OptimisticLockerConfig {
    /**
     * 樂觀鎖插件
     */
    @Bean
    public MybatisPlusInterceptor optimisticLockerInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

樂觀鎖使用示例:

@Service
public class OptimisticLockService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 樂觀鎖更新示例
     */
    public boolean updateWithOptimisticLock(Long userId, String newEmail) {
        // 先查詢獲取當(dāng)前版本號
        User user = userMapper.selectById(userId);
        if (user == null) {
            return false;
        }
        // 更新數(shù)據(jù),版本號會自動+1
        user.setEmail(newEmail);
        int result = userMapper.updateById(user);
        // result為0表示更新失?。ò姹咎枦_突)
        return result > 0;
    }
    /**
     * 重試機制的樂觀鎖更新
     */
    public boolean updateWithRetry(Long userId, String newEmail, int maxRetries) {
        for (int i = 0; i < maxRetries; i++) {
            User user = userMapper.selectById(userId);
            if (user == null) {
                return false;
            }
            user.setEmail(newEmail);
            int result = userMapper.updateById(user);
            if (result > 0) {
                return true;
            }
            // 短暫等待后重試
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }
        return false;
    }
}

第六章:總結(jié)與展望

6.1 知識點總結(jié)與技術(shù)擴展

通過本文的深入學(xué)習(xí),我們?nèi)嬲莆樟薓ybatis-Plus的核心功能和實戰(zhàn)應(yīng)用。讓我們來總結(jié)一下關(guān)鍵知識點:

6.1.1 核心知識點回顧

基礎(chǔ)配置與環(huán)境搭建

  • Mybatis-Plus的"只做增強不做改變"設(shè)計理念
  • SpringBoot集成配置和依賴管理
  • 數(shù)據(jù)源配置和連接池優(yōu)化
  • 全局配置和插件配置

實體注解與CRUD操作

  • @TableName、@TableId@TableField等核心注解
  • BaseMapper接口提供的豐富CRUD方法
  • IService接口的高級封裝和批量操作
  • 自動填充和審計功能的實現(xiàn)

條件構(gòu)造器與復(fù)雜查詢

  • QueryWrapper和UpdateWrapper的靈活使用
  • Lambda表達式條件構(gòu)造器的類型安全特性
  • 動態(tài)條件構(gòu)建和復(fù)雜查詢組合
  • 分頁查詢和自定義SQL的結(jié)合

代碼生成器與自動化開發(fā)

  • 代碼生成器的配置和自定義模板
  • 批量生成和項目集成策略
  • Maven插件和配置文件管理
  • 企業(yè)級代碼規(guī)范和最佳實踐

高級特性與性能優(yōu)化

  • 分頁插件的配置和性能優(yōu)化
  • 邏輯刪除的實現(xiàn)和數(shù)據(jù)安全保障
  • 樂觀鎖機制和并發(fā)控制
  • 自動填充和審計日志功能

6.1.2 技術(shù)擴展與深入學(xué)習(xí)

微服務(wù)架構(gòu)中的應(yīng)用

// 分布式事務(wù)中的Mybatis-Plus應(yīng)用
@Service
@Transactional
public class DistributedUserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderService orderService;
    /**
     * 分布式事務(wù)場景下的用戶創(chuàng)建
     */
    @GlobalTransactional
    public void createUserWithOrder(User user, Order order) {
        // 創(chuàng)建用戶
        userMapper.insert(user);
        // 調(diào)用訂單服務(wù)
        orderService.createOrder(order);
    }
}

緩存集成與性能優(yōu)化

// Redis緩存集成
@Service
public class CachedUserService extends ServiceImpl<UserMapper, User> {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Cacheable(value = "user", key = "#id")
    public User getById(Long id) {
        return super.getById(id);
    }
    @CacheEvict(value = "user", key = "#user.id")
    public boolean updateById(User user) {
        return super.updateById(user);
    }
}

多數(shù)據(jù)源配置

@Configuration
public class MultiDataSourceConfig {
    @Primary
    @Bean("masterDataSource")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean("slaveDataSource")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("master", masterDataSource());
        dataSourceMap.put("slave", slaveDataSource());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
        return dynamicDataSource;
    }
}

6.2 學(xué)習(xí)資源與參考資料

6.2.1 官方文檔與權(quán)威資源

官方文檔

權(quán)威書籍推薦

  • 《MyBatis從入門到精通》- 劉增輝著,系統(tǒng)學(xué)習(xí)MyBatis基礎(chǔ)
  • 《Spring Boot實戰(zhàn)》- Craig Walls著,深入理解SpringBoot
  • 《Java并發(fā)編程實戰(zhàn)》- Brian Goetz著,理解并發(fā)和鎖機制
  • 《高性能MySQL》- Baron Schwartz著,數(shù)據(jù)庫性能優(yōu)化

6.2.2 優(yōu)質(zhì)技術(shù)博客與教程

技術(shù)社區(qū)推薦

開源項目學(xué)習(xí)

  • RuoYi-Vue - 基于SpringBoot+Mybatis-Plus的管理系統(tǒng)
  • Pig - 微服務(wù)架構(gòu)的快速開發(fā)平臺
  • Jeecg-Boot - 低代碼開發(fā)平臺
  • SpringBlade - 微服務(wù)架構(gòu)的開發(fā)平臺

6.2.3 工具與插件推薦

開發(fā)工具

  • MybatisX插件 - IDEA中的Mybatis增強插件,提供XML和Mapper跳轉(zhuǎn)
  • Free Mybatis Plugin - 免費的Mybatis插件,支持代碼生成
  • MyBatis Log Plugin - SQL日志格式化插件
  • Database Navigator - 數(shù)據(jù)庫管理和SQL執(zhí)行工具

性能監(jiān)控工具

  • Druid監(jiān)控 - 阿里巴巴開源的數(shù)據(jù)庫連接池監(jiān)控
  • P6Spy - SQL語句攔截和性能分析
  • SkyWalking - 分布式系統(tǒng)性能監(jiān)控
  • Arthas - Java應(yīng)用診斷工具

6.3 技術(shù)發(fā)展趨勢與實踐建議

6.3.1 技術(shù)發(fā)展趨勢分析

云原生數(shù)據(jù)庫支持
隨著云計算的發(fā)展,Mybatis-Plus正在加強對云原生數(shù)據(jù)庫的支持,包括:

  • 多云數(shù)據(jù)庫適配
  • Serverless數(shù)據(jù)庫集成
  • 云數(shù)據(jù)庫的自動擴縮容支持

響應(yīng)式編程支持

// 未來可能的響應(yīng)式API設(shè)計
@Service
public class ReactiveUserService {
    @Autowired
    private ReactiveUserMapper userMapper;
    public Mono<User> findById(Long id) {
        return userMapper.selectById(id);
    }
    public Flux<User> findAll() {
        return userMapper.selectAll();
    }
}

AI輔助開發(fā)

  • 智能SQL優(yōu)化建議
  • 自動化性能調(diào)優(yōu)
  • 基于機器學(xué)習(xí)的查詢優(yōu)化

6.3.2 最佳實踐建議

性能優(yōu)化建議

  1. 合理使用分頁查詢,避免大數(shù)據(jù)量查詢
  2. 啟用SQL日志,監(jiān)控慢查詢并優(yōu)化
  3. 使用連接池監(jiān)控,及時發(fā)現(xiàn)連接泄露
  4. 合理設(shè)置緩存策略,提高查詢性能

代碼規(guī)范建議

  1. 統(tǒng)一實體類設(shè)計,繼承審計基類
  2. 規(guī)范命名約定,保持代碼可讀性
  3. 合理使用條件構(gòu)造器,避免復(fù)雜的嵌套查詢
  4. 編寫單元測試,保證代碼質(zhì)量

安全性建議

  1. 啟用邏輯刪除,保護重要數(shù)據(jù)
  2. 使用樂觀鎖,處理并發(fā)更新
  3. 參數(shù)校驗,防止SQL注入
  4. 敏感字段加密,保護用戶隱私

6.4 互動與討論

6.4.1 開放性問題探討

讓我們一起思考以下幾個深度技術(shù)問題:

問題1:性能優(yōu)化策略
在高并發(fā)場景下,如何平衡Mybatis-Plus的便利性和性能要求?你會選擇哪些優(yōu)化策略?

問題2:微服務(wù)架構(gòu)適配
在微服務(wù)架構(gòu)中,如何設(shè)計Mybatis-Plus的數(shù)據(jù)訪問層?如何處理分布式事務(wù)和數(shù)據(jù)一致性?

問題3:代碼生成器定制
如何根據(jù)企業(yè)的代碼規(guī)范,定制適合團隊的代碼生成器模板?有哪些最佳實踐?

問題4:多數(shù)據(jù)源管理
在復(fù)雜的業(yè)務(wù)場景中,如何優(yōu)雅地管理多數(shù)據(jù)源?如何實現(xiàn)讀寫分離和數(shù)據(jù)庫切換?

問題5:未來發(fā)展方向
你認(rèn)為Mybatis-Plus在云原生和響應(yīng)式編程方面應(yīng)該如何發(fā)展?有哪些期待的新特性?

6.4.2 實戰(zhàn)挑戰(zhàn)項目

挑戰(zhàn)項目1:企業(yè)級用戶管理系統(tǒng)
使用Mybatis-Plus構(gòu)建一個完整的用戶管理系統(tǒng),包括:

  • 用戶注冊、登錄、權(quán)限管理
  • 分頁查詢、條件搜索、批量操作
  • 審計日志、邏輯刪除、樂觀鎖
  • 性能監(jiān)控、SQL優(yōu)化、緩存集成

挑戰(zhàn)項目2:微服務(wù)數(shù)據(jù)訪問層
設(shè)計一個微服務(wù)架構(gòu)的數(shù)據(jù)訪問層,實現(xiàn):

  • 多數(shù)據(jù)源動態(tài)切換
  • 分布式事務(wù)管理
  • 讀寫分離和負載均衡
  • 數(shù)據(jù)同步和一致性保證

6.4.3 社區(qū)交流與學(xué)習(xí)

技術(shù)交流方式

  • GitHub討論區(qū) - 參與開源項目討論,提交Issue和PR
  • 技術(shù)QQ群/微信群 - 加入Mybatis-Plus技術(shù)交流群
  • 技術(shù)會議和Meetup - 參加線下技術(shù)分享活動
  • 博客和視頻分享 - 分享自己的學(xué)習(xí)心得和實戰(zhàn)經(jīng)驗

持續(xù)學(xué)習(xí)建議

  1. 關(guān)注官方動態(tài) - 及時了解新版本特性和更新
  2. 實踐項目應(yīng)用 - 在實際項目中應(yīng)用所學(xué)知識
  3. 參與開源貢獻 - 為開源項目貢獻代碼和文檔
  4. 分享學(xué)習(xí)心得 - 通過博客、視頻等方式分享經(jīng)驗

結(jié)語

Mybatis-Plus作為優(yōu)秀的持久層增強工具,極大地提升了Java開發(fā)者的工作效率。通過本文的深入學(xué)習(xí),相信你已經(jīng)掌握了從基礎(chǔ)配置到高級特性的全面知識。

技術(shù)的學(xué)習(xí)是一個持續(xù)的過程,希望這篇文章能夠成為你Mybatis-Plus學(xué)習(xí)路上的重要參考。在實際項目中,要根據(jù)具體業(yè)務(wù)需求選擇合適的技術(shù)方案,在便利性和性能之間找到最佳平衡點。

到此這篇關(guān)于Mybatis-Plus 實戰(zhàn)使用與最佳實踐的文章就介紹到這了,更多相關(guān)Mybatis-Plus 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java如何按16進制發(fā)送和接收TCP指令

    Java如何按16進制發(fā)送和接收TCP指令

    這篇文章主要介紹了Java如何按16進制發(fā)送和接收TCP指令問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java SpringBoot詳解集成以及配置Swagger流程

    Java SpringBoot詳解集成以及配置Swagger流程

    Swagger 是一個規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化 RESTful 風(fēng)格的 Web 服務(wù)。總體目標(biāo)是使客戶端和文件系統(tǒng)作為服務(wù)器以同樣的速度來更新。文件的方法,參數(shù)和模型緊密集成到服務(wù)器端的代碼,允許API來始終保持同步
    2021-10-10
  • Java Arraylist在多線程環(huán)境下的問題與解決方案

    Java Arraylist在多線程環(huán)境下的問題與解決方案

    這篇文章主要介紹了關(guān)于arraylist的多線程問題以及多種場景下的解決方案,同時詳細簡述了其核心內(nèi)容和原理,希望對大家有一定的幫助
    2026-03-03
  • bool當(dāng)成函數(shù)參數(shù)錯誤理解

    bool當(dāng)成函數(shù)參數(shù)錯誤理解

    經(jīng)常會在函數(shù)的參數(shù)里使用bool參數(shù),這會大大地降低代碼的可讀性
    2012-11-11
  • Seata?AT模式前后鏡像是如何生成詳解

    Seata?AT模式前后鏡像是如何生成詳解

    這篇文章主要為大家介紹了Seata?AT模式前后鏡像是如何生成的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • Java如何使用Set接口存儲沒有重復(fù)元素的數(shù)組

    Java如何使用Set接口存儲沒有重復(fù)元素的數(shù)組

    Set是一個繼承于Collection的接口,即Set也是集合中的一種。Set是沒有重復(fù)元素的集合,本篇我們就用它存儲一個沒有重復(fù)元素的數(shù)組
    2022-04-04
  • 深入了解Java中finalize方法的作用和底層原理

    深入了解Java中finalize方法的作用和底層原理

    這篇文章主要為大家詳細介紹了Java中finalize方法的作用和底層原理,文中的示例代碼講解詳細,具有一定的學(xué)習(xí)價值,需要的可以參考一下
    2022-12-12
  • Java中增強for循環(huán)代碼示例

    Java中增強for循環(huán)代碼示例

    這篇文章主要給大家介紹了Java中增強for循環(huán)的相關(guān)資料,for/in循環(huán)就是JDK5.0中所謂的增強For循環(huán),它能對數(shù)組和集合進行遍歷,使用它會使用你的代碼短小而精煉的多,需要的朋友可以參考下
    2023-10-10
  • springMVC發(fā)送郵件的簡單實現(xiàn)

    springMVC發(fā)送郵件的簡單實現(xiàn)

    本篇文章主要介紹了springMVC發(fā)送郵件的簡單實現(xiàn) ,主要是利用利用javax.mail發(fā)送郵件,圖片與附件都可發(fā)送,有興趣的可以了解一下
    2017-04-04
  • java設(shè)計模式學(xué)習(xí)之代理模式

    java設(shè)計模式學(xué)習(xí)之代理模式

    這篇文章主要為大家詳細介紹了java設(shè)計模式學(xué)習(xí)之代理模式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10

最新評論

西平县| 杭锦旗| 观塘区| 新晃| 华宁县| 乳山市| 清水县| 永嘉县| 平安县| 西昌市| 静乐县| 西城区| 无为县| 曲阜市| 宝兴县| 华容县| 西平县| 运城市| 临洮县| 波密县| 老河口市| 泗洪县| 石泉县| 大关县| 五河县| 象州县| 鄂托克前旗| 贡嘎县| 阿拉善左旗| 灌云县| 临高县| 都兰县| 长汀县| 平远县| 荃湾区| 唐海县| 东莞市| 柳州市| 康马县| 德江县| 沐川县|