【Spring实战】@Service和@Mapper:业务与数据的“黄金搭档”!

💡 开篇故事:一次“找不到Bean”引发的深夜加班

程序员小赵正赶工一个电商项目,信心满满地写好了用户注册逻辑:

public class UserService {
    private UserMapper userMapper;  // 注入MyBatis的Mapper接口
    
    public void register(User user) {
        userMapper.insert(user);  // 调用数据库插入操作
    }
}

然而,一运行就报错:NullPointerException: userMapper is null!小赵抓狂:“明明UserMapper定义了@Mapper注解啊?!” 直到他给UserService加上 @Service,并在启动类添加 @MapperScan,代码终于跑通了…… 原来,这两个注解是“共生关系”!


🔍 第一章:@Service——业务逻辑的“指挥官”
1. 什么是@Service?
  • 身份标识:Spring的组件扫描注解之一,专用于标记**业务逻辑层(Service层)**的类。
  • 核心职责
    • 被Spring容器管理,支持依赖注入(如注入Mapper、Repository等)。
    • 通过事务管理(@Transactional)保障业务操作的原子性。
2. 为什么不用@Component?
  • 语义化差异
    • @Component 是通用注解,而 @Service 明确表示“这是业务服务”!
    • 代码可读性更强,分层架构更清晰。
3. 实战代码
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
}

关键点

  • 类上标注 @Service → Spring自动创建单例Bean。
  • 通过@Autowired 注入其他Bean(如Mapper)。

🔍 第二章:@Mapper——MyBatis的“SQL翻译官”
1. 什么是@Mapper?
  • MyBatis的核心注解:标记一个接口为**数据访问层(Mapper层)**组件。
  • 核心职责
    • MyBatis动态生成接口实现类,无需手动写SQL实现!
    • 与XML映射文件或注解SQL配合,执行数据库操作。
2. 为什么不用@Repository?
  • 框架差异
    • @Repository 是Spring对数据访问层的通用注解。
    • @Mapper 是MyBatis的特有注解,专为MyBatis接口设计。
  • 关键区别
    • @Mapper 接口由MyBatis动态代理实现,而非Spring容器。
    • 需配合 @MapperScan 指定扫描路径。
3. 实战代码

接口定义

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectById(Long id);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    int insert(User user);
}

XML映射文件(可选)

<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectById" resultType="User">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

🎬 第三章:@Service + @Mapper 协同作战
1. 依赖注入流程

  1. Spring容器扫描 @Service → 创建 UserService Bean。
  2. MyBatis扫描 @Mapper → 生成 UserMapper 代理类。
  3. Spring将 UserMapper 代理对象注入到 UserService 中。
2. 完整调用链示例
@RestController
public class UserController {
    @Autowired
    private UserService userService;  // 注入Service

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);  // Service调用Mapper
    }
}

❗ 第四章:避坑指南 & 高频问题
1. Q:为什么Mapper接口无法注入?
  • 检查项
    1. 是否添加了 @Mapper 注解?
    2. 启动类是否配置了 @MapperScan("com.example.mapper")?
    3. Mapper接口与XML文件是否在同一包下且命名一致?
2. Q:Service层需要加事务吗?
  • 推荐做法:在Service方法上加 @Transactional!
    @Service
    public class OrderService {
        @Transactional  // 事务管理
        public void createOrder(Order order) {
            orderMapper.insert(order);
            inventoryMapper.deductStock(order.getProductId());
        }
    }
    
3. Q:@MapperScan有什么用?
  • 作用:指定MyBatis扫描Mapper接口的包路径。
  • 示例
    @SpringBootApplication
    @MapperScan("com.example.mapper")  // 指定Mapper接口所在包
    public class Application { ... }
    
4. Q:Service和Mapper能否跨模块调用?
  • 可以!确保:
    • Mapper接口在 @MapperScan 指定的扫描范围内。
    • Service类所在包被Spring组件扫描覆盖(默认扫描启动类同级目录)。

🚀 第五章:进阶技巧——更高效地使用Service与Mapper
1. 使用MyBatis-Plus简化Mapper开发
@Mapper
public interface UserMapper extends BaseMapper<User> { 
    // 继承BaseMapper即拥有CRUD方法,无需写SQL!
}
2. 服务层接口与实现分离
public interface UserService {
    User getUserById(Long id);
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(Long id) { ... }
}

优势:面向接口编程,方便扩展和Mock测试。

3. 批量操作优化
@Mapper
public interface BatchMapper {
    void batchInsert(@Param("list") List<User> users);
}

<!-- XML中批量插入 -->
<insert id="batchInsert">
    INSERT INTO user (name, age) VALUES
    <foreach collection="list" item="user" separator=",">
        (#{user.name}, #{user.age})
    </foreach>
</insert>

🌟 总结:分工明确,协作无间
  • @Service:业务逻辑的“大脑”,负责调度和事务管理。
  • @Mapper:数据操作的“手”,专注SQL执行与结果映射。
  • 最佳实践
    • Service层处理业务规则,Mapper层只做数据访问。
    • 结合事务注解保障数据一致性。

📢 互动话题:你在Service和Mapper的配合使用中踩过哪些坑?或者有什么高效的使用技巧?评论区一起聊聊吧!👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值