当前位置: 首页 > news >正文

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);// 方法结束时自动提交事务,异常时自动回滚}}
}

集成优势:

  1. 自动资源管理 - Spring自动管理SqlSession的创建和关闭
  2. 声明式事务 - 使用@Transactional注解管理事务
  3. 依赖注入 - Mapper接口可以直接注入到Service中
  4. 异常转换 - 将MyBatis异常转换为Spring的DataAccessException
  5. 配置简化 - 统一的配置管理

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的集成:

  1. 集成优势:自动资源管理、声明式事务、依赖注入
  2. 核心组件:SqlSessionFactoryBean、MapperScannerConfigurer、SqlSessionTemplate
  3. 事务管理:声明式事务和编程式事务
  4. 高级特性:多数据源、分页插件、性能监控
  5. 最佳实践:异常处理、性能优化、配置管理

MyBatis与Spring集成的关键点:

  • 理解各个组件的作用和配置方法
  • 正确配置事务管理,确保数据一致性
  • 合理使用缓存和分页功能
  • 做好异常处理和性能监控
  • 遵循最佳实践,提高代码质量

🔗 下一篇预告

下一篇文章将介绍SpringMVC请求处理与控制器,深入学习SpringMVC的请求处理机制和Controller的高级用法。


相关文章:

  • 上一篇:MyBatis缓存机制与性能优化
  • 下一篇:SpringMVC请求处理与控制器
  • 返回目录
http://www.dtcms.com/a/344880.html

相关文章:

  • 计算机内存中的整型存储奥秘、大小端字节序及其判断方法
  • Bluedroid vs NimBLE
  • 北京-测试-入职甲方金融-上班第三天
  • AR眼镜巡检系统在工业互联网的应用:AR+IoT
  • JAVA后端开发——API状态字段设计规范与实践
  • 目标检测数据集转换为图像分类数据集
  • Pandas中的SettingWithCopyWarning警告出现原因及解决方法
  • 共享内存详细解释
  • 前端在WebSocket中加入Token的方法
  • 12-Linux系统用户管理及基础权限
  • 塞尔达传说 王国之泪 PC/手机双端 免安装中文版
  • celery
  • C语言翻译环境作业
  • 大学校园安消一体化平台——多警合一实现智能联动与网格化管理
  • 【链表 - LeetCode】19. 删除链表的倒数第 N 个结点
  • Android.mk 基础
  • Electron 核心 API 全解析:从基础到实战场景
  • 从零开始搭 Linux 环境:VMware 下 CentOS 7 的安装与配置全流程(附图解)
  • openstack的novnc兼容问题
  • 【日常学习】2025-8-20 框架中控件子类实例化设计
  • FPGA学习笔记——简单的IIC读写EEPROM
  • LeetCode 3195.包含所有 1 的最小矩形面积 I:简单题-求长方形四个范围
  • 化工生产场景下设备状态监测与智能润滑预测性维护路径
  • 校园作品互评管理移动端的设计与实现
  • Boost库中boost::random::normal_distribution(正态分布)详解和实战示例
  • 腾讯云EdgeOne安全防护:快速上手,全面抵御Web攻击
  • 如何优雅的监听dom的变化(尺寸)
  • php apache无法接收到Authorization header
  • JDK17 升级避坑指南:技术原理与解决方案详解
  • 【学习记录】structuredClone,URLSearchParams,groupBy