一、核心概念

  1. Service接口

    • 业务层抽象,定义CRUD操作方法
    • 继承MyBatis-Plus的IService<T>接口获得基础方法
  2. ServiceImpl实现类

    • 服务接口的具体实现
    • 继承ServiceImpl<Mapper<T>, T>获得默认实现
    • 需添加@Service注解

二、详细操作步骤

步骤1:配置代码生成器(续接实体类生成)

public class CodeGenerator {
    public static void main(String[] args) {
        // ... [全局配置、数据源配置省略] ...

        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.example.project");
        packageConfig.setEntity("entity");
        packageConfig.setMapper("mapper");
        packageConfig.setService("service");      // Service接口包名
        packageConfig.setServiceImpl("service.impl"); // 实现类包名
        generator.setPackageInfo(packageConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        
        // 重点配置:Service生成选项
        strategy.setServiceGenerateEnable(true); // 启用Service生成
        strategy.setSuperServiceClass("com.example.project.base.BaseService"); // 自定义父接口
        strategy.setSuperServiceImplClass("com.example.project.base.BaseServiceImpl"); // 自定义父实现
        strategy.setInclude("user", "product"); // 生成对应表的Service
        
        generator.setStrategy(strategy);
        
        // ... [模板引擎配置省略] ...
        generator.execute();
    }
}

步骤2:自定义Service模板(可选)

  1. 复制默认模板到resources/templates

    • service.java.ftl(接口模板)
    • serviceImpl.java.ftl(实现类模板)
  2. 修改模板内容(示例简化接口):

// serviceImpl.java.ftl
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> 
    implements ${table.serviceName} {
    // 简化默认方法
    public boolean save(${entity} entity) {
        return retBool(baseMapper.insert(entity));
    }
}

步骤3:生成文件结构

src/main/java
└── com
    └── example
        └── project
            ├── entity
            ├── mapper
            └── service
                ├── UserService.java         # Service接口
                └── impl
                    ├── UserServiceImpl.java # 实现类

三、常见错误及解决

  1. Service方法调用报空指针

    • 原因:未在Controller中注入Service
    • 解决:添加@Autowired注解
    @RestController
    public class UserController {
        @Autowired  // 关键注入
        private UserService userService;
    }
    
  2. 事务失效问题

    • 现象:@Transactional注解不生效
    • 解决:
      @Service
      public class UserServiceImpl extends ... {
          // 正确:在public方法上添加注解
          @Transactional(rollbackFor = Exception.class)
          public void batchCreate(List<User> users) {
              // ...
          }
      }
      
      避免在同类非事务方法中调用事务方法
  3. 多数据源Service报错

    • 错误:No qualifying bean of type 'UserService'
    • 解决:在启动类排除自动配置
      @SpringBootApplication(exclude = {
          DataSourceAutoConfiguration.class
      })
      

四、注意事项

  1. 服务层职责边界

    • Service应包含业务逻辑,避免直接操作Mapper
    • 事务管理应在Service层完成
  2. 方法覆盖原则

    • 需要修改默认CRUD实现时:
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> {
        // 覆盖默认查询方法
        @Override
        public User getById(Serializable id) {
            // 自定义逻辑
            return super.getById(id);
        }
    }
    
  3. 泛型传递规范

    • 正确声明泛型类型:
    // ✅ 正确
    public interface UserService extends IService<User> 
    
    // ❌ 错误(缺少泛型参数)
    public class UserServiceImpl extends ServiceImpl<UserMapper>
    

五、高级使用技巧

  1. 链式查询封装

    // 在Service接口中添加
    default QueryChainWrapper<User> queryChain() {
        return new QueryChainWrapper<>(getBaseMapper());
    }
    
    // 使用示例
    User user = userService.queryChain()
         .eq("status", 1)
         .like("name", "John")
         .one();
    
  2. 多表关联查询

    @Service
    public class OrderServiceImpl ... {
        public OrderDetailVO getDetail(Long orderId) {
            // 在Service层做数据组装
            Order order = getById(orderId);
            User user = userService.getById(order.getUserId());
            return new OrderDetailVO(order, user);
        }
    }
    
  3. 服务熔断降级

    @Service
    public class PaymentService {
        @HystrixCommand(fallbackMethod = "defaultPayment")
        public boolean pay(Order order) { ... }
    
        private boolean defaultPayment(Order order) {
            // 降级逻辑
        }
    }
    

六、性能优化方案

  1. 批量操作优化

    @Service
    public class UserServiceImpl ... {
        // 使用批处理模式
        @Transactional
        public void batchInsert(List<User> users) {
            saveBatch(users, 1000); // 每1000条提交一次
        }
    }
    
  2. 读写分离配置

    @Master // 自定义注解
    @Override
    public boolean save(User entity) {
        // 写操作路由到主库
        return super.save(entity);
    }
    
    @Slave // 从库查询
    @Override
    public User getById(Serializable id) {
        return super.getById(id);
    }
    
  3. 二级缓存启用

    # application.yml
    mybatis-plus:
      configuration:
        cache-enabled: true
    

    在Service方法添加缓存注解:

    @Cacheable(value = "users", key = "#id")
    @Override
    public User getById(Long id) { ... }
    

七、最佳实践

  1. 服务分层架构

    service/
    ├── UserService.java          # 接口定义
    ├── impl/
    │   └── UserServiceImpl.java  # 基础实现
    └── ext/                      # 扩展服务
        └── UserServiceExt.java   # 业务增强接口
    
  2. DTO分离原则

    @Service
    public class UserServiceImpl ... {
        // 使用DTO接收参数
        public UserDTO createUser(UserCreateDTO dto) {
            User user = convert(dto, User.class);
            save(user);
            return convert(user, UserDTO.class);
        }
    }
    
  3. 服务监控集成

    @Timed(value = "user_service_time", description = "用户服务耗时")
    @Counted(value = "user_service_count", description = "用户服务调用次数")
    @Override
    public User getById(Long id) { ... }
    

生成结果示例

Service接口:

public interface UserService extends IService<User> {
    // 自定义业务方法
    List<User> findInactiveUsers(LocalDateTime lastLoginBefore);
}

ServiceImpl实现类:

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

    @Override
    public List<User> findInactiveUsers(LocalDateTime lastLoginBefore) {
        return lambdaQuery()
                .lt(User::getLastLoginTime, lastLoginBefore)
                .eq(User::getActive, false)
                .list();
    }
    
    // 覆盖默认删除方法
    @Override
    @Transactional
    public boolean removeById(Serializable id) {
        // 添加审计日志
        log.info("Deleting user: {}", id);
        return super.removeById(id);
    }
}

执行效果验证:

@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService userService;

    @Test
    void testBatchCreate() {
        List<User> users = generateTestUsers(10000);
        userService.batchInsert(users); // 批量插入1w条数据
    }
}

关键要点

  1. Service层应聚焦业务逻辑,基础CRUD交给MyBatis-Plus默认实现
  2. 事务控制在Service层实现
  3. 复杂查询使用LambdaQueryWrapper保持代码可读性
  4. 批量操作注意设置合理的批处理大小(500-2000条/批)
  5. 高并发场景考虑添加@Cacheable缓存注解

通过合理使用MyBatis-Plus的Service生成功能,可减少70%以上的重复CRUD代码,同时保持架构的扩展性和可维护性。