spring boot一课一得

Spring Boot 凭借 “约定优于配置” 的核心理念,大幅降低了 Spring 框架的使用门槛,成为后端开发的主流选择。在学习过程中,我从搭建基础项目起步,逐步深入核心功能整合,其中Spring Boot 整合 MyBatis全局异常处理是我收获最显著的两个知识点 —— 前者解决了数据持久化的核心需求,后者则完善了接口的健壮性设计。以下结合具体学习过程、代码实战和原理拆解,分享我的学习心得。

一、核心知识点 1:Spring Boot 整合 MyBatis—— 数据持久化的落地实践

1. 学习背景与痛点

初学阶段,我已掌握 Spring Boot 的基础接口开发,但面对 “数据库操作” 时,原生 JDBC 代码繁琐、手动管理连接池易出错。MyBatis 作为半自动化的 ORM 框架,既能灵活编写 SQL,又能简化数据操作,而 Spring Boot 与 MyBatis 的整合是后端开发的高频场景。最初我困惑于:如何让 Spring Boot 识别 MyBatis 的 Mapper 接口?如何实现配置简化和 SQL 复用?

2. 分步骤学习与实战

步骤 1:环境搭建与基础整合

首先完成最简化的整合,核心是依赖引入和核心配置。

  • 引入依赖(pom.xml)
  • <!-- Spring Boot核心依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent> <!-- Web依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis整合Spring Boot依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.3.2</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- 数据源(HikariCP,Spring Boot默认) --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <!-- 测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
  • 核心配置(application.yml):配置数据源和 MyBatis 核心参数,替代传统 MyBatis 的mybatis-config.xml
  • spring: # 数据源配置 datasource: url: jdbc:mysql://localhost:3306/spring_boot_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # HikariCP连接池配置(可选,Spring Boot默认启用) hikari: maximum-pool-size: 10 # 最大连接数 minimum-idle: 5 # 最小空闲连接数 idle-timeout: 30000 # 空闲连接超时时间 # MyBatis配置 mybatis: mapper-locations: classpath:mapper/*.xml # Mapper XML文件路径 type-aliases-package: com.example.demo.entity # 实体类别名包 configuration: map-underscore-to-camel-case: true # 开启下划线转驼峰命名 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志
  • 步骤 2:核心代码实现(三层架构)

    采用 “实体类→Mapper 接口→Service→Controller” 的经典分层结构,实现用户信息的 CRUD。

  • 实体类(User.java):对应数据库tb_user表,开启下划线转驼峰后,user_name可自动映射到userName
  • package com.example.demo.entity; import lombok.Data; @Data // Lombok简化getter/setter public class User { private Long id; private String userName; private String email; private Integer age; private String createTime; }
  • Mapper 接口(UserMapper.java):MyBatis 的核心接口,无需实现类,通过注解或 XML 编写 SQL。
  • package com.example.demo.mapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.*; import org.springframework.stereotype.Repository; import java.util.List; @Repository // 标识为持久层组件 public interface UserMapper { // 注解方式编写SQL(简单SQL) @Select("SELECT * FROM tb_user WHERE id = #{id}") User selectById(Long id); // XML方式编写SQL(复杂SQL,推荐) List<User> selectList(User user); @Insert("INSERT INTO tb_user(user_name, email, age, create_time) VALUES(#{userName}, #{email}, #{age}, #{createTime})") @Options(useGeneratedKeys = true, keyProperty = "id") // 回填自增ID int insert(User user); @Update("UPDATE tb_user SET user_name = #{userName}, email = #{email}, age = #{age} WHERE id = #{id}") int update(User user); @Delete("DELETE FROM tb_user WHERE id = #{id}") int delete(Long id); }
  • Mapper XML 文件(UserMapper.xml):放在resources/mapper目录下,编写复杂查询 SQL。
  • <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.mapper.UserMapper"> <!-- 通用查询结果列 --> <sql id="Base_Column_List"> id, user_name, email, age, create_time </sql> <!-- 条件查询 --> <select id="selectList" parameterType="com.example.demo.entity.User" resultType="com.example.demo.entity.User"> SELECT <include refid="Base_Column_List"/> FROM tb_user <where> <if test="userName != null and userName != ''"> AND user_name LIKE CONCAT('%', #{userName}, '%') </if> <if test="email != null and email != ''"> AND email = #{email} </if> <if test="age != null"> AND age = #{age} </if> </where> </select> </mapper>
  • Service 层(UserService.java):封装业务逻辑,调用 Mapper 接口。
  • package com.example.demo.service; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.List; @Service public class UserService { @Resource // 注入Mapper private UserMapper userMapper; public User getById(Long id) { return userMapper.selectById(id); } public List<User> list(User user) { return userMapper.selectList(user); } @Transactional // 开启事务 public int add(User user) { return userMapper.insert(user); } @Transactional public int edit(User user) { return userMapper.update(user); } @Transactional public int remove(Long id) { return userMapper.delete(id); } }
  • Controller 层(UserController.java):提供 RESTful 接口,接收前端请求。
  • package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; @RestController @RequestMapping("/user") public class UserController { @Resource private UserService userService; @GetMapping("/{id}") public User getById(@PathVariable Long id) { return userService.getById(id); } @PostMapping("/list") public List<User> list(@RequestBody User user) { return userService.list(user); } @PostMapping("/add") public String add(@RequestBody User user) { int count = userService.add(user); return count > 0 ? "新增成功,用户ID:" + user.getId() : "新增失败"; } @PutMapping("/edit") public String edit(@RequestBody User user) { int count = userService.edit(user); return count > 0 ? "修改成功" : "修改失败"; } @DeleteMapping("/{id}") public String remove(@PathVariable Long id) { int count = userService.remove(id); return count > 0 ? "删除成功" : "删除失败"; } }
  • 启动类(DemoApplication.java):关键是添加@MapperScan注解,扫描 Mapper 接口所在包。
  • package com.example.demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.demo.mapper") // 扫描Mapper接口包 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
  • 核心关键点

  • @MapperScan:替代传统 MyBatis 的MapperScannerConfigurer,自动扫描 Mapper 接口并生成动态代理对象;
  • 自动配置:MyBatisAutoConfiguration类完成SqlSessionFactorySqlSessionTemplate等核心组件的自动配置;
  • 动态代理:Mapper 接口无需实现类,MyBatis 通过 JDK 动态代理生成代理对象,接管 SQL 执行逻辑;
  • 下划线转驼峰:map-underscore-to-camel-case: true解决数据库字段(如user_name)与实体类属性(如userName)的映射问题。
  • 步骤 3:进阶优化 —— 分页插件整合

    实际开发中分页是高频需求,整合 MyBatis-Plus 的分页插件(无需引入完整 MyBatis-Plus):

  • 引入分页插件依赖:
  • <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency>
  • 配置分页插件:
  • package com.example.demo.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件(MySQL) interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }
  • 分页查询实战:
  • // Service层新增分页方法 public IPage<User> page(Page<User> page, User user) { return userMapper.selectPage(page, new QueryWrapper<User>() .like(StringUtils.isNotBlank(user.getUserName()), "user_name", user.getUserName()) .eq(StringUtils.isNotBlank(user.getEmail()), "email", user.getEmail()) .eq(user.getAge() != null, "age", user.getAge())); } // Controller层 @PostMapping("/page") public IPage<User> page(@RequestBody PageParam param) { Page<User> page = new Page<>(param.getPageNum(), param.getPageSize()); User user = new User(); user.setUserName(param.getUserName()); user.setEmail(param.getEmail()); user.setAge(param.getAge()); return userService.page(page, user); }
  • 3. 学习心得

    Spring Boot 整合 MyBatis 的核心是 “自动配置 + 约定”:

  • 简化了传统 MyBatis 的SqlSessionFactoryMapperScanner等配置,通过少量 yml 配置即可完成整合;
  • 注解与 XML 结合的 SQL 编写方式,兼顾了简单 SQL 的便捷性和复杂 SQL 的可读性;
  • 动态代理和分页插件的使用,让数据操作更高效,也让我理解了 “框架封装底层,开发者聚焦业务” 的设计思想。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值