SSM从入门到实战: 2.7 MyBatis与Spring集成
👋 大家好,我是 阿问学长
!专注于分享优质开源项目
解析、毕业设计项目指导
支持、幼小初高
的教辅资料
推荐等,欢迎关注交流!🚀
14-MyBatis与Spring集成
📖 本文概述
本文是SSM框架系列MyBatis进阶篇的第四篇,将详细介绍MyBatis与Spring框架的集成方法。通过完整的配置示例和最佳实践,帮助读者掌握在Spring环境中使用MyBatis的核心技术。
🎯 学习目标
- 理解MyBatis与Spring集成的原理和优势
- 掌握MyBatis-Spring的配置方法
- 学会使用Spring管理MyBatis的事务
- 了解Mapper接口的自动注入机制
- 掌握集成环境下的最佳实践
1. MyBatis-Spring集成概述
1.1 集成的优势
MyBatis与Spring集成带来的主要优势:
/*** 集成前后对比*/
public class IntegrationComparison {/*** 原生MyBatis使用方式*/public void withoutSpring() {SqlSession sqlSession = null;try {// 手动管理SqlSessionsqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 手动管理事务User user = userMapper.findById(1L);user.setUsername("updated");userMapper.update(user);// 手动提交事务sqlSession.commit();} catch (Exception e) {// 手动回滚事务if (sqlSession != null) {sqlSession.rollback();}throw e;} finally {// 手动关闭资源if (sqlSession != null) {sqlSession.close();}}}/*** Spring集成后的使用方式*/@Service@Transactionalpublic class UserService {@Autowiredprivate UserMapper userMapper; // 自动注入public void updateUser(Long id, String username) {// Spring自动管理SqlSession和事务User user = userMapper.findById(id);user.setUsername(username);userMapper.update(user);// 方法结束时自动提交事务,异常时自动回滚}}
}
集成优势:
- 自动资源管理 - Spring自动管理SqlSession的创建和关闭
- 声明式事务 - 使用@Transactional注解管理事务
- 依赖注入 - Mapper接口可以直接注入到Service中
- 异常转换 - 将MyBatis异常转换为Spring的DataAccessException
- 配置简化 - 统一的配置管理
1.2 集成架构
Spring + MyBatis 集成架构:┌─────────────────────────────────────────────────────────────┐
│ Spring容器 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Service层 │ │
│ │ @Autowired UserMapper userMapper │ │
│ │ @Transactional │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Mapper代理对象 │ │
│ │ (由MapperFactoryBean创建) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SqlSessionTemplate │ │
│ │ (线程安全的SqlSession) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SqlSessionFactory │ │
│ │ (由SqlSessionFactoryBean创建) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘│▼
┌─────────────────────────────────────────────────────────────┐
│ 数据库 │
└─────────────────────────────────────────────────────────────┘
2. 环境搭建和依赖配置
2.1 Maven依赖
<properties><spring.version>5.3.21</spring.version><mybatis.version>3.5.10</mybatis.version><mybatis-spring.version>2.0.7</mybatis-spring.version><mysql.version>8.0.33</mysql.version><druid.version>1.2.16</druid.version>
</properties><dependencies><!-- Spring核心依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><!-- MyBatis依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!-- MyBatis-Spring集成依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>${mybatis-spring.version}</version></dependency><!-- 数据库相关 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency>
</dependencies>
2.2 Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 加载属性文件 --><context:property-placeholder location="classpath:database.properties"/><!-- 开启注解扫描 --><context:component-scan base-package="com.example.service"/><!-- 数据源配置 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="driverClassName" value="${database.driver}"/><property name="url" value="${database.url}"/><property name="username" value="${database.username}"/><property name="password" value="${database.password}"/><property name="initialSize" value="10"/><property name="maxActive" value="50"/><property name="minIdle" value="10"/><property name="maxWait" value="60000"/></bean><!-- MyBatis SqlSessionFactory配置 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/><property name="mapperLocations" value="classpath:mybatis/mappers/*.xml"/><property name="typeAliasesPackage" value="com.example.entity"/></bean><!-- MyBatis Mapper扫描配置 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.example.mapper"/><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/></bean><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 开启事务注解支持 --><tx:annotation-driven transaction-manager="transactionManager"/></beans>
3. 核心组件详解
3.1 SqlSessionFactoryBean
SqlSessionFactoryBean是MyBatis-Spring的核心组件,用于创建SqlSessionFactory:
/*** SqlSessionFactoryBean配置示例*/
@Configuration
public class MyBatisConfig {@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();// 设置数据源factoryBean.setDataSource(dataSource);// 设置MyBatis配置文件factoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));// 设置Mapper XML文件位置factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mappers/*.xml"));// 设置类型别名包factoryBean.setTypeAliasesPackage("com.example.entity");// 设置类型处理器factoryBean.setTypeHandlers(new TypeHandler[]{new LocalDateTimeTypeHandler()});// 设置插件factoryBean.setPlugins(new Interceptor[]{new PageInterceptor() // 分页插件});// 设置全局配置org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(true);configuration.setLazyLoadingEnabled(true);factoryBean.setConfiguration(configuration);return factoryBean.getObject();}
}
3.2 MapperScannerConfigurer
MapperScannerConfigurer用于自动扫描和注册Mapper接口:
/*** Mapper扫描配置*/
@Configuration
public class MapperScanConfig {/*** 方式1:使用@MapperScan注解*/@MapperScan(basePackages = "com.example.mapper",sqlSessionFactoryRef = "sqlSessionFactory",annotationClass = Repository.class // 只扫描带@Repository注解的接口)static class MapperScanConfiguration {}/*** 方式2:使用MapperScannerConfigurer Bean*/@Beanpublic MapperScannerConfigurer mapperScannerConfigurer() {MapperScannerConfigurer configurer = new MapperScannerConfigurer();configurer.setBasePackage("com.example.mapper");configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");configurer.setAnnotationClass(Repository.class);return configurer;}
}
3.3 SqlSessionTemplate
SqlSessionTemplate是线程安全的SqlSession实现:
/*** SqlSessionTemplate使用示例*/
@Repository
public class UserDaoImpl implements UserDao {@Autowiredprivate SqlSessionTemplate sqlSessionTemplate;@Overridepublic User findById(Long id) {return sqlSessionTemplate.selectOne("com.example.mapper.UserMapper.findById", id);}@Overridepublic List<User> findAll() {return sqlSessionTemplate.selectList("com.example.mapper.UserMapper.findAll");}@Overridepublic void insert(User user) {sqlSessionTemplate.insert("com.example.mapper.UserMapper.insert", user);}@Overridepublic void update(User user) {sqlSessionTemplate.update("com.example.mapper.UserMapper.update", user);}@Overridepublic void deleteById(Long id) {sqlSessionTemplate.delete("com.example.mapper.UserMapper.deleteById", id);}
}/*** SqlSessionTemplate配置*/
@Configuration
public class SqlSessionTemplateConfig {@Beanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}@Beanpublic SqlSessionTemplate batchSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);}
}
4. 事务管理集成
4.1 声明式事务配置
/*** 事务管理配置*/
@Configuration
@EnableTransactionManagement
public class TransactionConfig {@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}/*** 服务层事务使用示例*/
@Service
@Transactional(readOnly = true) // 类级别默认只读事务
public class UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RoleMapper roleMapper;/*** 只读事务*/public User findById(Long id) {return userMapper.findById(id);}/*** 读写事务*/@Transactional(readOnly = false, rollbackFor = Exception.class)public void saveUser(User user, List<Long> roleIds) {// 保存用户userMapper.insert(user);// 保存用户角色关联for (Long roleId : roleIds) {userMapper.insertUserRole(user.getId(), roleId);}// 如果这里抛出异常,整个事务会回滚if (user.getUsername().equals("error")) {throw new RuntimeException("模拟异常");}}/*** 新事务*/@Transactional(propagation = Propagation.REQUIRES_NEW)public void auditLog(String operation, String details) {// 审计日志使用独立事务,不受主业务事务影响AuditLog log = new AuditLog();log.setOperation(operation);log.setDetails(details);log.setCreateTime(new Date());auditLogMapper.insert(log);}/*** 复杂事务场景*/@Transactional(isolation = Isolation.READ_COMMITTED,timeout = 30,rollbackFor = {Exception.class},noRollbackFor = {IllegalArgumentException.class})public void complexBusinessOperation(User user) {// 复杂的业务逻辑validateUser(user);userMapper.update(user);updateRelatedData(user);// 记录审计日志(使用新事务)auditLog("UPDATE_USER", "更新用户: " + user.getId());}
}
4.2 编程式事务
/*** 编程式事务示例*/
@Service
public class ProgrammaticTransactionService {@Autowiredprivate TransactionTemplate transactionTemplate;@Autowiredprivate UserMapper userMapper;/*** 使用TransactionTemplate*/public void transferMoney(Long fromUserId, Long toUserId, BigDecimal amount) {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus status) {try {// 扣减转出账户User fromUser = userMapper.findById(fromUserId);if (fromUser.getBalance().compareTo(amount) < 0) {throw new InsufficientFundsException("余额不足");}fromUser.setBalance(fromUser.getBalance().subtract(amount));userMapper.update(fromUser);// 增加转入账户User toUser = userMapper.findById(toUserId);toUser.setBalance(toUser.getBalance().add(amount));userMapper.update(toUser);} catch (Exception e) {// 手动回滚status.setRollbackOnly();throw e;}}});}/*** 使用PlatformTransactionManager*/@Autowiredprivate PlatformTransactionManager transactionManager;public void manualTransactionControl() {TransactionDefinition def = new DefaultTransactionDefinition();TransactionStatus status = transactionManager.getTransaction(def);try {// 业务逻辑User user = new User();user.setUsername("test");userMapper.insert(user);// 提交事务transactionManager.commit(status);} catch (Exception e) {// 回滚事务transactionManager.rollback(status);throw e;}}
}
5. 高级特性集成
5.1 多数据源配置
/*** 多数据源配置*/
@Configuration
public class MultiDataSourceConfig {@Bean@Primary@ConfigurationProperties(prefix = "spring.datasource.primary")public DataSource primaryDataSource() {return DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.secondary")public DataSource secondaryDataSource() {return DruidDataSourceBuilder.create().build();}@Bean@Primarypublic SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/primary/*.xml"));return factoryBean.getObject();}@Beanpublic SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/secondary/*.xml"));return factoryBean.getObject();}@Bean@Primarypublic PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Beanpublic PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}/*** 多数据源Mapper配置*/
@MapperScan(basePackages = "com.example.mapper.primary",sqlSessionFactoryRef = "primarySqlSessionFactory"
)
@Configuration
public class PrimaryMapperConfig {
}@MapperScan(basePackages = "com.example.mapper.secondary",sqlSessionFactoryRef = "secondarySqlSessionFactory"
)
@Configuration
public class SecondaryMapperConfig {
}
5.2 分页插件集成
/*** PageHelper分页插件配置*/
@Configuration
public class PageHelperConfig {@Beanpublic PageInterceptor pageInterceptor() {PageInterceptor pageInterceptor = new PageInterceptor();Properties properties = new Properties();properties.setProperty("helperDialect", "mysql");properties.setProperty("reasonable", "true");properties.setProperty("supportMethodsArguments", "true");properties.setProperty("params", "count=countSql");pageInterceptor.setProperties(properties);return pageInterceptor;}
}/*** 分页查询服务*/
@Service
public class PageQueryService {@Autowiredprivate UserMapper userMapper;public PageInfo<User> findUsersByPage(int pageNum, int pageSize, String keyword) {// 开启分页PageHelper.startPage(pageNum, pageSize);// 执行查询List<User> users = userMapper.findByKeyword(keyword);// 封装分页信息return new PageInfo<>(users);}
}
6. 最佳实践
6.1 异常处理
/*** MyBatis异常处理*/
@ControllerAdvice
public class MyBatisExceptionHandler {@ExceptionHandler(DataAccessException.class)public ResponseEntity<String> handleDataAccessException(DataAccessException e) {logger.error("数据访问异常", e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("数据访问失败");}@ExceptionHandler(DuplicateKeyException.class)public ResponseEntity<String> handleDuplicateKeyException(DuplicateKeyException e) {logger.warn("数据重复", e);return ResponseEntity.status(HttpStatus.CONFLICT).body("数据已存在");}
}
6.2 性能监控
/*** MyBatis性能监控*/
@Component
public class MyBatisPerformanceMonitor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime = System.currentTimeMillis();try {Object result = invocation.proceed();long endTime = System.currentTimeMillis();// 记录执行时间if (endTime - startTime > 1000) { // 超过1秒的慢查询logger.warn("慢查询检测: {}ms, SQL: {}", endTime - startTime, getSql(invocation));}return result;} catch (Exception e) {logger.error("SQL执行异常: {}", getSql(invocation), e);throw e;}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 设置属性}private String getSql(Invocation invocation) {// 提取SQL语句的逻辑return "SQL statement";}
}
7. 小结
本文详细介绍了MyBatis与Spring的集成:
- 集成优势:自动资源管理、声明式事务、依赖注入
- 核心组件:SqlSessionFactoryBean、MapperScannerConfigurer、SqlSessionTemplate
- 事务管理:声明式事务和编程式事务
- 高级特性:多数据源、分页插件、性能监控
- 最佳实践:异常处理、性能优化、配置管理
MyBatis与Spring集成的关键点:
- 理解各个组件的作用和配置方法
- 正确配置事务管理,确保数据一致性
- 合理使用缓存和分页功能
- 做好异常处理和性能监控
- 遵循最佳实践,提高代码质量
🔗 下一篇预告
下一篇文章将介绍SpringMVC请求处理与控制器,深入学习SpringMVC的请求处理机制和Controller的高级用法。
相关文章:
- 上一篇:MyBatis缓存机制与性能优化
- 下一篇:SpringMVC请求处理与控制器
- 返回目录