SpringBoot整合MyBatis实战与最佳实践
2026/9/14 21:42:15 网站建设 项目流程

1. SpringBoot与MyBatis整合概述

在Java企业级应用开发中,SpringBoot和MyBatis是两个最常用的框架。SpringBoot提供了快速构建独立、生产级Spring应用的能力,而MyBatis则是一个优秀的持久层框架,它消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。两者的结合能够极大提升开发效率和代码可维护性。

MyBatis的核心优势在于其SQL与Java代码的分离设计。与Hibernate等全自动ORM框架不同,MyBatis允许开发者直接编写原生SQL,同时通过XML或注解方式将SQL与Java对象映射起来。这种半自动化的设计既保留了SQL的灵活性,又简化了数据库操作。

2. 环境准备与项目配置

2.1 依赖引入

在SpringBoot项目中使用MyBatis,首先需要在pom.xml中添加相关依赖:

<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>

mybatis-spring-boot-starter是MyBatis官方提供的SpringBoot启动器,它会自动配置MyBatis所需的基本组件,包括SqlSessionFactory、SqlSessionTemplate等。

2.2 数据源配置

在application.properties或application.yml中配置数据源:

spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

注意:在生产环境中,建议将数据库密码等敏感信息存储在配置中心或使用环境变量,而不是直接写在配置文件中。

3. MyBatis基础使用

3.1 实体类与Mapper接口

首先定义一个简单的实体类:

public class User { private Long id; private String name; private Integer age; private String email; // getters and setters }

然后创建对应的Mapper接口:

@Mapper public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") User findById(Long id); @Insert("INSERT INTO user(name, age, email) VALUES(#{name}, #{age}, #{email})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert(User user); @Update("UPDATE user SET name=#{name}, age=#{age}, email=#{email} WHERE id=#{id}") int update(User user); @Delete("DELETE FROM user WHERE id=#{id}") int delete(Long id); }

@Mapper注解告诉MyBatis这是一个Mapper接口,SpringBoot启动时会自动扫描并创建实现类。@Select、@Insert等注解则用于定义SQL语句。

3.2 XML映射文件

对于复杂的SQL,建议使用XML映射文件。首先在application.properties中配置XML文件位置:

mybatis.mapper-locations=classpath:mapper/*.xml

然后创建对应的XML文件:

<?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.mapper.UserMapper"> <resultMap id="userResultMap" type="com.example.entity.User"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="email" column="email"/> </resultMap> <select id="findAll" resultMap="userResultMap"> SELECT * FROM user </select> <select id="findByCondition" resultMap="userResultMap"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="age != null"> AND age = #{age} </if> </where> </select> </mapper>

4. 高级特性与最佳实践

4.1 动态SQL

MyBatis提供了强大的动态SQL功能,可以根据不同条件生成不同的SQL语句:

<update id="updateSelective" parameterType="com.example.entity.User"> UPDATE user <set> <if test="name != null">name = #{name},</if> <if test="age != null">age = #{age},</if> <if test="email != null">email = #{email},</if> </set> WHERE id = #{id} </update>

4.2 分页查询

SpringBoot整合MyBatis实现分页有多种方式:

  1. 使用PageHelper插件:
PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.findAll(); PageInfo<User> pageInfo = new PageInfo<>(users);
  1. 使用MyBatis-Plus的分页插件(如果项目中使用MyBatis-Plus)

  2. 手动编写分页SQL:

<select id="findByPage" resultMap="userResultMap"> SELECT * FROM user LIMIT #{offset}, #{pageSize} </select>

4.3 事务管理

SpringBoot中默认已经配置了事务管理,只需在Service层方法上添加@Transactional注解即可:

@Service public class UserService { @Autowired private UserMapper userMapper; @Transactional public void updateUser(User user) { userMapper.update(user); // 其他数据库操作 } }

注意:@Transactional默认只对RuntimeException及其子类异常回滚,如果需要其他异常也触发回滚,可以指定rollbackFor属性。

5. 常见问题与解决方案

5.1 映射问题

问题描述:数据库字段与Java属性名不一致导致映射失败。

解决方案

  1. 使用@Results注解:
@Results({ @Result(property = "userName", column = "user_name"), @Result(property = "userAge", column = "user_age") }) @Select("SELECT user_name, user_age FROM user WHERE id = #{id}") User findUserWithDifferentColumnNames(Long id);
  1. 在XML中使用resultMap(推荐):
<resultMap id="userResultMap" type="User"> <result property="userName" column="user_name"/> <result property="userAge" column="user_age"/> </resultMap>

5.2 缓存问题

MyBatis有一级缓存和二级缓存:

  • 一级缓存:SqlSession级别,默认开启
  • 二级缓存:Mapper级别,需要手动配置

开启二级缓存

  1. 在配置文件中:
mybatis.configuration.cache-enabled=true
  1. 在Mapper接口上添加注解:
@CacheNamespace public interface UserMapper { // ... }

或者在XML映射文件中:

<mapper namespace="com.example.mapper.UserMapper"> <cache/> <!-- 其他配置 --> </mapper>

注意:二级缓存可能导致脏读问题,在分布式环境下需要特别小心。

5.3 性能优化

  1. 批量操作
@Insert("<script>" + "INSERT INTO user(name, age, email) VALUES " + "<foreach collection='list' item='item' separator=','>" + "(#{item.name}, #{item.age}, #{item.email})" + "</foreach>" + "</script>") void batchInsert(List<User> users);
  1. 延迟加载: 在配置文件中开启:
mybatis.configuration.lazy-loading-enabled=true mybatis.configuration.aggressive-lazy-loading=false

然后在关联查询中使用:

<resultMap id="userWithOrders" type="User"> <collection property="orders" column="id" select="com.example.mapper.OrderMapper.findByUserId" fetchType="lazy"/> </resultMap>

6. 实际项目中的经验分享

6.1 多数据源配置

在实际项目中,经常需要连接多个数据库。SpringBoot中配置多数据源:

  1. 定义多个数据源配置类:
@Configuration @MapperScan(basePackages = "com.example.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate") public class PrimaryDataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/primary/*.xml")); return bean.getObject(); } @Bean public SqlSessionTemplate primarySqlSessionTemplate( @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
  1. 在application.properties中配置多个数据源:
# 主数据源 spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db spring.datasource.primary.username=root spring.datasource.primary.password=123456 spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver # 从数据源 spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db spring.datasource.secondary.username=root spring.datasource.secondary.password=123456 spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

6.2 枚举类型处理

MyBatis提供了TypeHandler来处理Java枚举类型与数据库值的转换:

  1. 创建自定义TypeHandler:
public class UserStatusTypeHandler extends BaseTypeHandler<UserStatus> { @Override public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.getCode()); } @Override public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException { return UserStatus.fromCode(rs.getInt(columnName)); } // 其他重载方法... }
  1. 注册TypeHandler:
@MappedTypes(UserStatus.class) @MappedJdbcTypes(JdbcType.INTEGER) public class UserStatusTypeHandler extends BaseTypeHandler<UserStatus> { // ... }

或者在XML中指定:

<resultMap id="userResultMap" type="User"> <result property="status" column="status" typeHandler="com.example.handler.UserStatusTypeHandler"/> </resultMap>

6.3 复杂查询优化

对于复杂的多表关联查询,建议:

  1. 使用DTO接收查询结果,而不是直接使用实体类:
public class UserOrderDTO { private String userName; private String orderNo; private BigDecimal amount; // getters and setters }
  1. 在XML中使用resultMap映射:
<resultMap id="userOrderResultMap" type="UserOrderDTO"> <result property="userName" column="user_name"/> <result property="orderNo" column="order_no"/> <result property="amount" column="amount"/> </resultMap> <select id="findUserOrders" resultMap="userOrderResultMap"> SELECT u.name as user_name, o.order_no, o.amount FROM user u JOIN orders o ON u.id = o.user_id WHERE u.id = #{userId} </select>

7. 测试与调试技巧

7.1 单元测试

SpringBoot提供了方便的测试支持:

@SpringBootTest public class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void testFindById() { User user = userMapper.findById(1L); assertNotNull(user); assertEquals("张三", user.getName()); } @Test @Transactional @Rollback public void testInsert() { User user = new User(); user.setName("李四"); user.setAge(25); user.setEmail("lisi@example.com"); int result = userMapper.insert(user); assertEquals(1, result); assertNotNull(user.getId()); } }

7.2 SQL日志输出

在开发阶段,可以开启MyBatis的SQL日志:

# 显示执行的SQL及其参数 logging.level.com.example.mapper=DEBUG

或者在配置类中配置:

@Configuration public class MyBatisConfig { @Bean public ConfigurationCustomizer mybatisConfigurationCustomizer() { return configuration -> { configuration.setLogImpl(StdOutImpl.class); }; } }

7.3 性能监控

集成Druid数据源监控:

  1. 添加依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency>
  1. 配置Druid:
spring.datasource.druid.stat-view-servlet.enabled=true spring.datasource.druid.stat-view-servlet.url-pattern=/druid/* spring.datasource.druid.stat-view-servlet.reset-enable=false spring.datasource.druid.stat-view-servlet.login-username=admin spring.datasource.druid.stat-view-servlet.login-password=admin

访问http://localhost:8080/druid即可查看SQL监控信息。

8. 项目结构建议

一个良好的项目结构能提高代码的可维护性:

src/main/java ├── com.example │ ├── config // 配置类 │ ├── controller // 控制器 │ ├── service // 服务层 │ │ ├── impl // 服务实现 │ ├── mapper // Mapper接口 │ ├── entity // 实体类 │ ├── dto // 数据传输对象 │ ├── vo // 视图对象 │ ├── handler // TypeHandler │ ├── interceptor // 拦截器 │ └── Application.java // 启动类 src/main/resources ├── mapper // XML映射文件 ├── static // 静态资源 ├── templates // 模板文件 └── application.properties

9. 版本兼容性与升级

不同版本的SpringBoot与MyBatis可能存在兼容性问题:

  • SpringBoot 2.5.x 推荐使用 mybatis-spring-boot-starter 2.2.x
  • SpringBoot 2.4.x 推荐使用 mybatis-spring-boot-starter 2.1.x
  • SpringBoot 2.3.x 推荐使用 mybatis-spring-boot-starter 2.1.x

升级时需要注意:

  1. 检查依赖兼容性
  2. 备份重要数据
  3. 逐步测试各个功能模块

10. 扩展与自定义

10.1 自定义插件

MyBatis允许开发插件来拦截核心方法执行:

@Intercepts({ @Signature(type= Executor.class, method="update", args={MappedStatement.class, Object.class}), @Signature(type= Executor.class, method="query", args={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) }) public class MyBatisInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { // 前置处理 Object result = invocation.proceed(); // 后置处理 return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // 设置属性 } }

然后在配置类中注册:

@Bean public MyBatisInterceptor myBatisInterceptor() { return new MyBatisInterceptor(); }

10.2 自定义TypeHandler

对于特殊的数据类型转换,可以创建自定义TypeHandler:

public class JsonTypeHandler<T> extends BaseTypeHandler<T> { private Class<T> type; public JsonTypeHandler(Class<T> type) { this.type = type; } @Override public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, JSON.toJSONString(parameter)); } @Override public T getNullableResult(ResultSet rs, String columnName) throws SQLException { String json = rs.getString(columnName); return json == null ? null : JSON.parseObject(json, type); } // 其他重载方法... }

使用方式:

@TableName(autoResultMap = true) public class User { @TableField(typeHandler = JsonTypeHandler.class) private List<String> tags; }

11. 安全注意事项

  1. SQL注入防护

    • 始终使用#{}而不是${}进行参数绑定
    • 对用户输入进行严格验证
    • 使用MyBatis的动态SQL标签而不是字符串拼接
  2. 敏感数据保护

    • 数据库密码等敏感信息应加密存储
    • 使用配置中心管理敏感配置
    • 限制数据库用户的权限
  3. 日志安全

    • 生产环境不应记录完整的SQL和参数
    • 敏感字段应在日志中脱敏

12. 性能调优建议

  1. 连接池配置
spring.datasource.druid.initial-size=5 spring.datasource.druid.min-idle=5 spring.datasource.druid.max-active=20 spring.datasource.druid.max-wait=60000 spring.datasource.druid.time-between-eviction-runs-millis=60000 spring.datasource.druid.min-evictable-idle-time-millis=300000
  1. MyBatis配置优化
mybatis.configuration.default-fetch-size=100 mybatis.configuration.default-statement-timeout=30 mybatis.configuration.map-underscore-to-camel-case=true
  1. 批量操作
@Transactional public void batchInsert(List<User> users) { SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH); try { UserMapper mapper = sqlSession.getMapper(UserMapper.class); for (User user : users) { mapper.insert(user); } sqlSession.commit(); } finally { sqlSession.close(); } }

13. 常见错误与解决方案

  1. Invalid bound statement (not found)

    • 检查Mapper接口是否被@Mapper注解或@MapperScan扫描到
    • 检查XML文件路径是否正确
    • 检查XML中的namespace是否与Mapper接口全限定名一致
  2. Parameter 'xxx' not found

    • 检查参数名是否与方法参数名一致
    • 使用@Param注解明确指定参数名:
    User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
  3. TooManyResultsException

    • 确保查询结果只有一条记录时使用selectOne
    • 或者修改查询条件确保结果唯一

14. 与其他技术整合

14.1 整合MyBatis-Plus

MyBatis-Plus是对MyBatis的增强:

  1. 添加依赖:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency>
  1. 创建通用Mapper:
public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> { }
  1. 使用示例:
@Service public class UserService { @Autowired private UserMapper userMapper; public Page<User> findUsers(int page, int size) { return userMapper.selectPage(new Page<>(page, size), null); } }

14.2 整合Redis缓存

  1. 添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
  1. 配置Redis:
spring.redis.host=localhost spring.redis.port=6379
  1. 使用缓存注解:
@Cacheable(value = "user", key = "#id") public User findById(Long id) { return userMapper.findById(id); }

15. 实际项目经验总结

  1. SQL管理

    • 复杂的SQL建议写在XML中
    • 简单的CRUD可以使用注解
    • 保持SQL的可读性,适当添加注释
  2. 事务边界

    • 事务应放在Service层
    • 避免长事务
    • 合理设置事务隔离级别和传播行为
  3. 代码生成

    • 使用MyBatis Generator或MyBatis-Plus代码生成器
    • 自定义模板以满足项目规范
    • 生成的代码应放在单独的模块或目录
  4. 监控与报警

    • 监控慢SQL
    • 设置连接池使用阈值报警
    • 定期检查数据库性能
  5. 文档维护

    • 维护数据字典
    • 记录重要的SQL变更
    • 编写数据库设计文档

通过以上全面的介绍,你应该已经掌握了在SpringBoot项目中集成和使用MyBatis的核心知识和技巧。实际项目中,还需要根据具体需求和团队规范进行适当调整和扩展。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询