在微服务架构大行其道的今天,SpringBoot+MyBatis组合已成为Java开发者最趁手的数据库操作利器。本文从零开始,总结我对Mybits的学习
一、为什么选择MyBatis?
2023年StackOverflow调查显示,MyBatis在Java持久层框架中占有率高达42%,其核心优势在于:
-
SQL可见性:直观看到每句SQL,便于优化
-
灵活映射:ResultMap实现复杂对象映射
-
动态SQL:XML标签实现条件动态拼接
-
轻量级:学习曲线平缓,与SpringBoot完美契合
二、手把手教学:从Hello World到生产级配置
2.1 初始化彩蛋(90%新手会踩的坑)
# 注意!SpringBoot 3.x的包名变革
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true
# 必须显式指定驱动类!
driver-class-name: com.mysql.cj.jdbc.Driver
🛠️ 连接池选型指南:
-
HikariCP:SpringBoot官方推荐,号称"快如闪电"
-
Druid:阿里出品,自带监控面板
-
Tomcat JDBC:传统项目过渡选择
2.2 Mapper接口的三种打开方式
方式一:注解派(极简主义)
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(@Param("id") Long id);
}
方式二:XML派(掌控全局)
<!-- resources/mapper/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
<select id="findByName" resultType="User">
SELECT * FROM user
WHERE user_name LIKE CONCAT('%',#{name},'%')
</select>
</mapper>
方式三:混搭风(灵活王者)
@Mapper
public interface OrderMapper {
// 简单查询用注解
@Select("SELECT COUNT(*) FROM orders")
int countAll();
// 复杂查询用XML
List<Order> searchComplexOrders(OrderQuery query);
}
💡 架构师说:中小型项目推荐混搭模式,核心业务用XML保证可维护性,边缘功能用注解提升开发速度。
三、动态SQL
3.1 基础连招:<where> + <if>
<select id="searchUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name LIKE #{name}
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
ORDER BY create_time DESC
</select>
🛡️ 防御式编程:永远使用<where>
标签代替原生WHERE,避免出现WHERE AND
这样的语法炸弹。
3.2 进阶奥义:<choose>的智慧
<select id="findProducts" resultType="Product">
SELECT * FROM products
<where>
<choose>
<when test="categoryIds != null">
category_id IN
<foreach item="id" collection="categoryIds"
open="(" separator="," close=")">
#{id}
</foreach>
</when>
<when test="keyword != null">
AND (name LIKE #{keyword} OR description LIKE #{keyword})
</when>
<otherwise>
AND is_hot = 1
</otherwise>
</choose>
</where>
</select>
🎯 业务场景:电商商品搜索页的多条件筛选,不同用户群体呈现不同默认排序。
四、开发者必备的救命锦囊
4.1 SQL调试三件套
-
P6spy:在控制台打印真实SQL
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/mydb
MyBatis参数美化:
<configuration>
<settings>
<setting name="logPrefix" value="🐞 MYBATIS DEBUG => "/>
</settings>
</configuration>
4.2 分页查询的优雅实现
PageHelper插件(快速上手)
PageHelper.startPage(1, 10);
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
五、从代码到部署:完整链路实践
5.1 多环境配置策略
# application-dev.yml
mybatis:
mapper-locations: classpath:mapper/**/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# application-prod.yml
mybatis:
configuration:
cache-enabled: true
lazy-loading-enabled: true
5.2 数据库迁移方案
Flyway配置示例:
-- V1__init_schema.sql
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(255) NOT NULL
);
-- V2__add_index.sql
CREATE INDEX idx_user_name ON user(user_name);
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
六、前方高能:常见天坑预警
6.1 事务失效的N种死法
错误案例:
@Service
public class UserService {
// 错误!直接调用同类方法不会走代理
public void createUser(User user) {
insertUser(user);
insertLog(user); // 第二个插入失败不会回滚
}
@Transactional
public void insertUser(User user) { ... }
@Transactional
public void insertLog(User user) { ... }
}
正确姿势:
@Service
public class UserService {
@Transactional
public void createUser(User user) {
userMapper.insert(user);
logService.insertLog(user); // 通过代理对象调用
}
}
6.2 类型处理器的暗雷
问题场景:
MySQL的TINYINT(1)
被MyBatis默认映射为Boolean,导致存2时报错
解决方案:
@MappedJdbcTypes(JdbcType.TINYINT)
@MappedTypes(Integer.class)
public class CustomBooleanTypeHandler extends BaseTypeHandler<Integer> {
// 实现类型转换逻辑
}
避坑指南(血泪经验)
-
事务管理:在Service层添加
@Transactional
-
参数传递:多个参数必须使用
@Param
注解 -
Lombok兼容:Entity类需要添加
@NoArgsConstructor
-
SQL注入防护:禁止使用
${}
进行字符串拼接
结语
SpringBoot与MyBatis的整合,就像咖啡遇上奶泡般完美。掌握本文技巧后,你将能:
✅ 快速搭建企业级数据访问层
✅ 轻松应对复杂查询场景
✅ 写出高性能的数据库操作代码