MyBatis与Spring/Spring Boot集成完整指南
MyBatis与Spring/Spring Boot深度集成指南
一、与Spring集成
1. SqlSessionFactoryBean
SqlSessionFactoryBean
是Spring和MyBatis集成的核心类,负责创建SqlSessionFactory
。
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws IOException {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mappers/*.xml"));
return factoryBean;
}
关键配置项:
dataSource
: 必须注入的数据源configLocation
: 指定MyBatis全局配置文件mapperLocations
: 指定Mapper XML文件位置typeAliasesPackage
: 实体类所在包,自动注册别名
实践建议:
- 生产环境建议显式指定
configLocation
,即使大部分配置可通过Spring完成 - 使用
mapperLocations
通配符匹配时注意路径规范
2. MapperScannerConfigurer
自动扫描Mapper接口并注册为Spring Bean:
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.example.mapper");
configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return configurer;
}
配置说明:
basePackage
: Mapper接口所在的包路径annotationClass
: 可指定自定义注解过滤接口sqlSessionFactoryBeanName
: 指定SqlSessionFactory的Bean名称
最佳实践:
- 将Mapper接口单独放在
mapper
或dao
包下 - 避免在Service层直接注入
SqlSession
3. 事务管理
Spring的事务管理可与MyBatis无缝集成:
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
事务配置要点:
- 使用
@Transactional
注解管理事务 - 默认情况下,每个Mapper方法都有自己的SqlSession
- 同一事务中的多个操作共享同一个SqlSession
常见问题解决:
// 解决事务内一级缓存失效问题
@Transactional
public void batchUpdate(List<User> users) {
// 手动控制SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
users.forEach(mapper::update);
sqlSession.commit();
} finally {
sqlSession.close();
}
}
二、与Spring Boot集成
1. 自动配置原理
Spring Boot通过mybatis-spring-boot-starter
提供自动配置:
graph TD
A[MybatisAutoConfiguration] --> B[SqlSessionFactory]
A --> C[SqlSessionTemplate]
B --> D[DataSource]
C --> B
E[MapperScannerRegistrar] --> F[扫描@Mapper接口]
关键自动配置类:
MybatisAutoConfiguration
: 核心配置类MybatisProperties
: 封装所有配置属性MapperScannerRegistrar
: 处理@MapperScan
2. 多数据源配置
@Configuration
public class MultiDataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "primarySqlSessionFactory")
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();
}
// 类似配置secondarySqlSessionFactory
}
多数据源事务管理:
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager primaryTransactionManager(
@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
使用建议:
- 明确标记
@Primary
数据源 - 不同数据源的Mapper接口和XML文件分开存放
- 使用
@Transactional
时指定事务管理器
三、代码生成器
1. MyBatis Generator配置
典型generatorConfig.xml
配置:
<context id="mysql" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test"
userId="root" password="123456"/>
<javaModelGenerator targetPackage="com.example.model"
targetProject="src/main/java"/>
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources"/>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.mapper"
targetProject="src/main/java"/>
<table tableName="user" domainObjectName="User"
enableCountByExample="false" enableUpdateByExample="false"/>
</context>
生成器类型选择:
ANNOTATEDMAPPER
: 生成注解版MapperXMLMAPPER
: 生成XML配置版MIXEDMAPPER
: 混合模式
2. 自定义插件示例
public class CustomPlugin extends PluginAdapter {
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable) {
// 添加Lombok注解
topLevelClass.addAnnotation("@Data");
topLevelClass.addAnnotation("@Builder");
topLevelClass.addAnnotation("@NoArgsConstructor");
topLevelClass.addAnnotation("@AllArgsConstructor");
return true;
}
}
生成器最佳实践:
- 将生成代码与手写代码分开管理
- 使用
.gitignore
忽略生成代码 - 自定义模板覆盖默认生成策略
四、TypeHandler深度应用
1. 自定义TypeHandler示例
处理JSON类型字段:
@MappedTypes({Map.class, List.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonTypeHandler extends BaseTypeHandler<Object> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Object parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, mapper.writeValueAsString(parameter));
}
@Override
public Object getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return parseJson(rs.getString(columnName));
}
private Object parseJson(String json) {
try {
return mapper.readValue(json, Object.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
2. 注册TypeHandler的三种方式
XML配置:
<typeHandlers> <typeHandler handler="com.example.handler.JsonTypeHandler"/> </typeHandlers>
Spring Boot配置:
mybatis.type-handlers-package=com.example.handler
注解方式:
@TableName(value = "user", autoResultMap = true) public class User { @TableField(typeHandler = JsonTypeHandler.class) private Map<String, Object> attributes; }
类型处理最佳实践:
- 复杂类型优先考虑JSON序列化方案
- 枚举类型实现
EnumTypeHandler
接口 - 敏感数据可在TypeHandler中加解密
五、集成常见问题解决方案
1. 事务不生效排查
检查清单:
- 确认
@EnableTransactionManagement
已启用 - 检查方法是否为
public
- 确认异常类型是否被捕获未抛出
- 不同数据源是否使用了正确的事务管理器
2. 多数据源动态切换
基于AOP的动态数据源路由:
@Aspect
@Component
@Order(-1) // 确保在事务注解前执行
public class DataSourceAspect {
@Before("@annotation(ds)")
public void before(DataSourceSwitch ds) {
String dsId = ds.value();
if (!DynamicDataSource.contains(dsId)) {
throw new IllegalArgumentException("数据源不存在");
}
DynamicDataSource.setDataSource(dsId);
}
@After("@annotation(ds)")
public void after(DataSourceSwitch ds) {
DynamicDataSource.clear();
}
}
3. 性能优化建议
批处理优化:
@Autowired private SqlSessionFactory sqlSessionFactory; public void batchInsert(List<User> users) { try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper mapper = session.getMapper(UserMapper.class); users.forEach(mapper::insert); session.commit(); } }
二级缓存配置:
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
延迟加载配置:
mybatis.configuration.lazy-loading-enabled=true mybatis.configuration.aggressive-lazy-loading=false
通过以上深度集成方案,可以充分发挥MyBatis在Spring生态中的优势,构建高效稳定的数据访问层。