Spring Boot整合MyBatis:企业级Java持久层实践

发布时间:2026/7/22 8:19:50
Spring Boot整合MyBatis:企业级Java持久层实践 1. Spring Boot与MyBatis整合概述在Java企业级应用开发中持久层框架的选择直接影响着系统的性能和开发效率。MyBatis作为一款优秀的半自动化ORM框架以其灵活的SQL映射和简洁的配置深受开发者喜爱。而Spring Boot的约定优于配置理念则大大简化了Spring应用的初始搭建和开发过程。将两者结合使用能够充分发挥各自的优势。我最近在一个电商后台管理系统的开发中就采用了Spring Boot MyBatis的技术组合。这个组合最吸引我的地方在于MyBatis提供了精准控制SQL的能力而Spring Boot则帮我们省去了大量样板代码和配置。特别是在需要处理复杂查询和性能优化的场景下这种组合展现出了强大的灵活性。2. 环境准备与项目搭建2.1 依赖配置首先创建一个新的Spring Boot项目推荐使用Spring Initializrhttps://start.spring.io/快速生成项目骨架。在pom.xml中需要添加以下核心依赖dependencies !-- Spring Boot Starter -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency !-- MyBatis Spring Boot Starter -- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version3.0.3/version /dependency !-- 数据库驱动 (以MySQL为例) -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- 其他可能需要的依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies注意MyBatis Spring Boot Starter的版本需要与你的Spring Boot版本匹配。Spring Boot 3.x建议使用MyBatis Starter 3.x版本Spring Boot 2.x则使用2.x版本。2.2 数据库配置在application.properties或application.yml中配置数据库连接信息# 数据源配置 spring.datasource.urljdbc:mysql://localhost:3306/your_database?useSSLfalseserverTimezoneUTC spring.datasource.usernameyour_username spring.datasource.passwordyour_password spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # MyBatis配置 mybatis.mapper-locationsclasspath:mapper/*.xml mybatis.type-aliases-packagecom.example.demo.model对于更复杂的配置可以在配置类中使用Java Config方式Configuration public class MyBatisConfig { Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setTypeAliasesPackage(com.example.demo.model); // 添加XML映射文件位置 Resource[] mapperLocations new PathMatchingResourcePatternResolver() .getResources(classpath:mapper/*.xml); sessionFactory.setMapperLocations(mapperLocations); // 其他配置 org.apache.ibatis.session.Configuration configuration new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); // 开启驼峰命名转换 sessionFactory.setConfiguration(configuration); return sessionFactory.getObject(); } }3. MyBatis核心组件集成3.1 Mapper接口与XML映射MyBatis的核心在于Mapper接口与SQL映射文件的配合使用。首先定义一个实体类Data // 使用Lombok简化代码 public class User { private Long id; private String username; private String email; private Date createTime; // getters and setters... }然后创建对应的Mapper接口Mapper // 关键注解标识这是一个MyBatis的Mapper接口 public interface UserMapper { Select(SELECT * FROM users WHERE id #{id}) User findById(Long id); Insert(INSERT INTO users(username, email, create_time) VALUES(#{username}, #{email}, #{createTime})) Options(useGeneratedKeys true, keyProperty id) int insert(User user); Update(UPDATE users SET username#{username}, email#{email} WHERE id#{id}) int update(User user); Delete(DELETE FROM users WHERE id#{id}) int delete(Long id); // 复杂查询可以使用XML映射 ListUser findByCondition(UserQuery query); }对于复杂SQL建议使用XML映射文件resources/mapper/UserMapper.xml?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.demo.mapper.UserMapper resultMap iduserResultMap typeUser id propertyid columnid/ result propertyusername columnusername/ result propertyemail columnemail/ result propertycreateTime columncreate_time/ /resultMap select idfindByCondition resultMapuserResultMap SELECT * FROM users where if testusername ! null and username ! AND username LIKE CONCAT(%, #{username}, %) /if if testemail ! null and email ! AND email #{email} /if if teststartTime ! null AND create_time #{startTime} /if if testendTime ! null AND create_time #{endTime} /if /where ORDER BY create_time DESC /select /mapper3.2 动态SQL实践MyBatis强大的动态SQL能力可以让我们根据不同条件构建灵活的查询语句。除了上面示例中的 标签MyBatis还提供了多种动态SQL元素!-- 使用choose-when-otherwise实现条件选择 -- select idfindActiveUser resultTypeUser SELECT * FROM users where choose when testactive true AND status 1 /when otherwise AND status 0 /otherwise /choose /where /select !-- 使用foreach实现批量操作 -- insert idbatchInsert parameterTypejava.util.List INSERT INTO users(username, email) VALUES foreach collectionlist itemuser separator, (#{user.username}, #{user.email}) /foreach /insert !-- 使用set标签动态更新 -- update idupdateSelective UPDATE users set if testusername ! nullusername#{username},/if if testemail ! nullemail#{email},/if /set WHERE id#{id} /update4. 高级特性与最佳实践4.1 事务管理Spring Boot与MyBatis整合后可以利用Spring强大的声明式事务管理Service public class UserService { Autowired private UserMapper userMapper; Transactional // 添加事务注解 public void createUser(User user) { userMapper.insert(user); // 其他数据库操作... } Transactional(readOnly true) // 只读事务 public User getUserWithDetail(Long id) { User user userMapper.findById(id); // 查询关联数据... return user; } }提示默认情况下Spring Boot会自动配置一个DataSourceTransactionManager来处理事务。如果需要更复杂的事务管理可以自定义TransactionManager。4.2 分页处理在Web应用中分页查询是常见需求。MyBatis有多种分页实现方式使用PageHelper插件推荐首先添加依赖dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version2.1.0/version /dependency然后在代码中使用public PageInfoUser getUsersByPage(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); ListUser users userMapper.findAll(); return new PageInfo(users); }使用MyBatis-Plus的分页插件如果项目中使用MyBatis-Plus手动实现分页适合简单场景Select(SELECT * FROM users LIMIT #{offset}, #{limit}) ListUser findUsersByPage(Param(offset) int offset, Param(limit) int limit);4.3 多数据源配置在实际项目中有时需要连接多个数据库。Spring Boot整合MyBatis实现多数据源的步骤如下配置多个数据源Configuration public class DataSourceConfig { Bean ConfigurationProperties(prefix spring.datasource.primary) public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } Bean ConfigurationProperties(prefix spring.datasource.secondary) public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } }为每个数据源配置独立的SqlSessionFactory和TransactionManagerConfiguration MapperScan(basePackages com.example.demo.mapper.primary, sqlSessionFactoryRef primarySqlSessionFactory) public class PrimaryMyBatisConfig { Bean public SqlSessionFactory primarySqlSessionFactory( Qualifier(primaryDataSource) DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); // 其他配置... return sessionFactory.getObject(); } Bean public PlatformTransactionManager primaryTransactionManager( Qualifier(primaryDataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } // 类似地配置secondary数据源...在application.properties中配置两个数据源的连接信息# 主数据源 spring.datasource.primary.urljdbc:mysql://localhost:3306/primary_db spring.datasource.primary.usernameroot spring.datasource.primary.password123456 spring.datasource.primary.driver-class-namecom.mysql.cj.jdbc.Driver # 次数据源 spring.datasource.secondary.urljdbc:mysql://localhost:3306/secondary_db spring.datasource.secondary.usernameroot spring.datasource.secondary.password123456 spring.datasource.secondary.driver-class-namecom.mysql.cj.jdbc.Driver5. 性能优化与常见问题5.1 缓存配置MyBatis提供了一级缓存和二级缓存机制一级缓存默认开启是SqlSession级别的缓存。在同一个SqlSession中相同的查询只会执行一次SQL。二级缓存需要手动开启是Mapper级别的缓存多个SqlSession共享。配置方式在MyBatis配置中开启二级缓存mybatis.configuration.cache-enabledtrue在Mapper接口上添加CacheNamespace注解CacheNamespace public interface UserMapper { // ... }或者在XML映射文件中添加 标签mapper namespacecom.example.demo.mapper.UserMapper cache/ !-- ... -- /mapper注意使用二级缓存时实体类需要实现Serializable接口。在高并发场景下建议使用Redis等分布式缓存替代MyBatis的二级缓存。5.2 常见问题排查Mapper接口无法注入确保Mapper接口有Mapper注解或在启动类上添加了MapperScan检查包扫描路径是否正确确认没有重复的Mapper idSQL语句执行报错检查SQL语法是否正确确认参数传递方式正确#{param} vs ${param}查看生成的SQL日志配置mybatis.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl事务不生效确保方法是被Spring代理调用的同类内部调用不会触发事务检查异常类型是否被正确捕获默认只对RuntimeException回滚确认使用的TransactionManager与数据源匹配性能问题检查是否使用了N1查询问题关联查询时确认是否合理使用了缓存分析慢SQL并优化5.3 监控与日志为了更好地监控MyBatis的性能可以配置以下内容开启SQL执行日志logging.level.com.example.demo.mapperDEBUG使用P6Spy打印完整SQL包含参数 添加依赖dependency groupIdp6spy/groupId artifactIdp6spy/artifactId version3.9.1/version /dependency修改数据源配置spring.datasource.urljdbc:p6spy:mysql://localhost:3306/your_database spring.datasource.driver-class-namecom.p6spy.engine.spy.P6SpyDriver添加spy.properties文件module.logcom.p6spy.engine.logging.P6LogFactory appendercom.p6spy.engine.spy.appender.StdoutLogger logMessageFormatcom.p6spy.engine.spy.appender.MultiLineFormat6. 实际项目中的经验分享在最近的一个电商项目中我们采用了Spring Boot MyBatis的技术栈积累了一些实战经验复杂查询处理 对于多表关联的复杂查询我们采用了以下策略使用 定义复杂的映射关系对于一对多关系使用 标签对于多对一关系使用 标签对于特别复杂的查询考虑拆分为多个简单查询在服务层组装批量操作优化 当需要处理大量数据插入/更新时使用MyBatis的批量执行器在SqlSessionFactory中配置executorTypeBATCH对于大批量数据考虑分批次处理使用 标签实现批量插入动态表名处理 在多租户系统中我们经常需要根据租户ID动态选择表名。实现方式SelectProvider(type UserSqlProvider.class, method findByTenant) ListUser findByTenant(Param(tenantId) String tenantId); public class UserSqlProvider { public String findByTenant(String tenantId) { return SELECT * FROM user_ tenantId WHERE status 1; } }枚举类型处理 MyBatis提供了EnumTypeHandler和EnumOrdinalTypeHandler来处理枚举类型。我们通常会自定义类型处理器public class StatusEnumTypeHandler extends BaseTypeHandlerStatusEnum { Override public void setNonNullParameter(PreparedStatement ps, int i, StatusEnum parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.getCode()); } // 其他方法实现... }然后在配置中注册Configuration public class MyBatisConfig { Bean public ConfigurationCustomizer mybatisConfigurationCustomizer() { return configuration - { configuration.getTypeHandlerRegistry() .register(StatusEnum.class, new StatusEnumTypeHandler()); }; } }SQL注入防护始终使用#{}而不是${}进行参数传递对用户输入进行严格的验证和过滤使用MyBatis的 标签处理LIKE查询select idsearch resultTypeUser bind namepattern value% keyword % / SELECT * FROM users WHERE username LIKE #{pattern} /selectSpring Boot与MyBatis的整合为Java开发者提供了一套高效、灵活的数据访问解决方案。通过合理的配置和使用可以充分发挥两者的优势构建出既灵活又高效的持久层。在实际项目中建议根据具体需求选择合适的特性组合并遵循最佳实践来保证代码质量和性能。