在 MyBatis-Plus (MP) 中,ServiceImpl<M extends BaseMapper<T>, T> 和 BaseMapper<T> 之间存在着紧密且明确的依赖和委托关系,它们分别代表了软件分层架构中的 Service 层实现 和 Data Access Object (DAO) / Mapper 层接口。
-
BaseMapper<T>- 数据访问层接口 (DAO/Mapper Interface):- 角色: 直接与数据库交互的接口。
- 核心功能: 继承自 MP 的
BaseMapper<T>接口后,自动获得了大量预定义的、通用的单表 CRUD(增删改查)方法实现(如insert,selectById,updateById,deleteById,selectList,selectPage等)。我们在开发时无需再为这些基础操作编写 SQL 语句。 - 关注点: 定义数据访问操作,封装 SQL 细节(虽然大部分基础 SQL 由 MP 自动生成)。
- 例子:
UserMapper extends BaseMapper<User>。
-
ServiceImpl<M extends BaseMapper<T>, T>- 服务层实现 (Service Implementation):- 角色: 业务逻辑层(Service Layer)的一个通用实现。它实现了 MP 提供的
IService<T>接口,后者定义了 Service 层常用的业务方法。 - 核心功能:
- 封装
BaseMapper:ServiceImpl内部持有一个对应的Mapper实例(类型为M,也就是继承了BaseMapper的那个接口,例如UserMapper)。这个 Mapper 实例通常通过依赖注入(如@Autowired)获得。 - 委托执行:
ServiceImpl中的许多(但不是全部)方法,其默认实现就是直接调用其内部持有的Mapper实例的相应方法来完成数据库操作。例如,ServiceImpl的getById(Serializable id)方法内部通常会调用baseMapper.selectById(id)。 - 提供额外便利方法:
ServiceImpl在IService接口的基础上,还提供了一些更方便的批量操作或组合操作方法,例如saveBatch(),saveOrUpdate(),updateBatchById()等,这些方法内部可能会调用Mapper的多个方法或进行一些逻辑处理。 - 事务管理: Service 层通常是应用声明式事务 (
@Transactional) 的地方。ServiceImpl的方法是添加事务注解的理想位置,确保一系列数据库操作(可能跨越多个 Mapper 调用)的原子性。 - 业务逻辑扩展点: 开发者可以继承
ServiceImpl并重写其方法,或者添加新的业务方法,在调用 Mapper 前后加入特定的业务校验、数据处理、组合逻辑等。
- 封装
- 关注点: 编排业务流程,处理业务逻辑,管理事务,调用并组合 Mapper 层操作。
- 例子:
UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService。
- 角色: 业务逻辑层(Service Layer)的一个通用实现。它实现了 MP 提供的
关系总结:
- 依赖关系:
ServiceImpl依赖于BaseMapper(具体体现为依赖其子接口,如UserMapper) 来执行实际的数据库操作。 - 委托关系:
ServiceImpl将大部分基础的数据访问任务委托给BaseMapper完成。 - 分层关系:
BaseMapper属于数据访问层 (DAO/Mapper),ServiceImpl属于业务逻辑层 (Service)。ServiceImpl是BaseMapper的使用者 (Consumer)。 - 功能扩展:
ServiceImpl在BaseMapper提供的原子数据库操作基础上,增加了业务封装、事务管理和更便捷的组合操作能力。
代码示例:
// 1. Entity
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
// Getters and Setters...
}
// 2. Mapper Interface (DAO Layer) - Extends BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
// BaseMapper already provides CRUD methods like insert, selectById, etc.
// Add custom complex SQL methods here if needed
// List<User> findUsersWithSpecialCondition(@Param("param") String param);
}
// 3. Service Interface (Service Layer - Optional but recommended)
public interface UserService extends IService<User> {
// IService already provides common service methods like getById, save, list, etc.
// Add custom business logic methods here
boolean updateUserName(Long userId, String newName);
}
// 4. Service Implementation (Service Layer) - Extends ServiceImpl, Implements UserService
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// ServiceImpl automatically injects the corresponding Mapper instance (named baseMapper)
// You can also @Autowired it explicitly if needed, though not necessary for basic usage:
// @Autowired
// private UserMapper userMapper; // This is the same instance as 'baseMapper' inherited from ServiceImpl
@Override
public User getUserById(Long id) {
// Example of ServiceImpl delegating to BaseMapper
// Calling the getById method inherited from ServiceImpl, which internally calls baseMapper.selectById(id)
return super.getById(id);
// Or directly use the inherited baseMapper:
// return baseMapper.selectById(id);
}
@Override
public boolean saveUser(User user) {
// Example of ServiceImpl providing convenience method 'save'
// Calling the save method inherited from ServiceImpl, which internally calls baseMapper.insert(user)
return super.save(user);
// Or directly:
// return baseMapper.insert(user) > 0;
}
@Override
@Transactional // Apply transaction at the service method level
public boolean updateUserName(Long userId, String newName) {
// Example of adding business logic in Service Layer
User user = baseMapper.selectById(userId); // Use inherited baseMapper
if (user != null) {
// Business validation or logic could go here
if (newName == null || newName.isEmpty()) {
throw new IllegalArgumentException("New name cannot be empty");
}
user.setName(newName);
// Delegate the update operation to baseMapper
return baseMapper.updateById(user) > 0;
// Alternatively, use the service method which also delegates
// return super.updateById(user);
}
return false;
}
// You can also directly use methods provided by ServiceImpl like saveOrUpdate, saveBatch etc.
// These methods encapsulate logic that might involve checking existence before insert/update
// or iterating and calling mapper methods multiple times.
public boolean createOrUpdate(User user) {
return super.saveOrUpdate(user); // Convenient method from ServiceImpl
}
}
通过这种设计,MP 实现了代码的复用(BaseMapper 和 ServiceImpl 的通用方法),保持了清晰的分层结构,并允许开发者在 Service 层轻松地添加业务逻辑和事务控制,同时极大地简化了数据访问层的开发工作。
437

被折叠的 条评论
为什么被折叠?



