您好,登录后才能下订单哦!
# 怎么把Mybatis整合到Spring中
## 前言
在现代Java企业级应用开发中,Spring框架和MyBatis持久层框架的组合被广泛使用。Spring提供了全面的基础设施支持,而MyBatis则以其灵活的SQL映射能力著称。本文将详细介绍如何将MyBatis整合到Spring框架中,涵盖从基础配置到高级特性的完整流程。
## 一、环境准备
### 1.1 所需依赖
在开始整合前,需要确保项目中包含以下核心依赖(以Maven为例):
```xml
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<!-- Spring JDBC事务支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.18</version>
</dependency>
<!-- MyBatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- MyBatis-Spring整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- 数据库驱动(以MySQL为例) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- 连接池(推荐HikariCP) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
推荐的项目结构组织方式:
src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── config/ # Spring配置类
│ │ ├── dao/ # MyBatis Mapper接口
│ │ ├── entity/ # 实体类
│ │ └── service/ # 业务服务层
│ └── resources/
│ ├── mapper/ # MyBatis映射文件
│ └── application.properties
首先配置数据源(以HikariCP为例):
@Configuration
@PropertySource("classpath:application.properties")
public class DataSourceConfig {
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
return new HikariDataSource(config);
}
}
对应的application.properties:
jdbc.url=jdbc:mysql://localhost:3306/mybatis_db?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
@Configuration
public class MyBatisConfig {
@Autowired
private DataSource dataSource;
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
// 配置类型别名包
factoryBean.setTypeAliasesPackage("com.example.entity");
// 配置mapper.xml文件位置
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/*.xml"));
// 可选:MyBatis配置
org.apache.ibatis.session.Configuration configuration =
new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
factoryBean.setConfiguration(configuration);
return factoryBean.getObject();
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.example.dao");
configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return configurer;
}
}
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Autowired
private DataSource dataSource;
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
public class User {
private Long id;
private String username;
private String email;
// 省略getter/setter
}
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User selectById(Long id);
@Insert("INSERT INTO users(username, email) VALUES(#{username}, #{email})")
@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);
}
对于复杂SQL,推荐使用XML配置:
<!-- resources/mapper/UserMapper.xml -->
<mapper namespace="com.example.dao.UserMapper">
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="email" column="email"/>
</resultMap>
<select id="selectByCondition" resultMap="userResultMap">
SELECT * FROM users
<where>
<if test="username != null">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="email != null">
AND email LIKE CONCAT('%', #{email}, '%')
</if>
</where>
</select>
</mapper>
集成PageHelper分页插件:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
@Bean
public PageInterceptor pageInterceptor() {
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
properties.setProperty("helperDialect", "mysql");
properties.setProperty("reasonable", "true");
pageInterceptor.setProperties(properties);
return pageInterceptor;
}
// 第一页,每页10条
PageHelper.startPage(1, 10);
List<User> users = userMapper.selectByCondition(params);
PageInfo<User> pageInfo = new PageInfo<>(users);
对于需要连接多个数据库的场景:
@Configuration
public class MultiDataSourceConfig {
@Primary
@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();
}
@Bean
public SqlSessionFactory primarySqlSessionFactory(
@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean
public SqlSessionFactory secondarySqlSessionFactory(
@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
// 为每个数据源配置独立的TransactionManager
}
实现AbstractRoutingDataSource实现动态切换:
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
// 使用ThreadLocal保存数据源标识
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceType(String type) {
contextHolder.set(type);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clear() {
contextHolder.remove();
}
}
// 通过AOP实现数据源切换
@Aspect
@Component
public class DataSourceAspect {
@Before("@annotation(dataSource)")
public void before(DataSource dataSource) {
DataSourceContextHolder.setDataSourceType(dataSource.value());
}
@After("@annotation(dataSource)")
public void after(DataSource dataSource) {
DataSourceContextHolder.clear();
}
}
SQL优化:
SELECT *
<foreach>
标签缓存策略:
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
连接池配置:
问题1:Mapper接口无法注入
- 检查@MapperScan
或MapperScannerConfigurer
配置的包路径是否正确
- 确保Mapper接口有@Mapper
注解或接口上有@Repository
注解
问题2:事务不生效
- 确保方法上有@Transactional
注解
- 检查是否启用了@EnableTransactionManagement
- 确认方法调用来自外部类(自调用不生效)
问题3:字段映射失败
- 检查数据库字段名与实体类属性名是否匹配
- 配置mapUnderscoreToCamelCase: true
开启驼峰转换
- 使用@Result
注解或<resultMap>
显式配置映射
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {DataSourceConfig.class, MyBatisConfig.class})
@Transactional
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
User user = new User();
user.setUsername("test");
user.setEmail("test@example.com");
int result = userMapper.insert(user);
assertEquals(1, result);
assertNotNull(user.getId());
}
}
@SpringBootTest
进行完整上下文测试通过本文的详细讲解,我们系统地了解了如何将MyBatis整合到Spring框架中。从基础的环境搭建、核心配置,到高级特性的实现和性能优化,这套整合方案能够满足大多数企业级应用的开发需求。正确合理地使用MyBatis-Spring整合,可以显著提高开发效率和系统性能。
在实际项目开发中,建议根据具体需求选择合适的配置方案,并持续关注MyBatis和Spring的版本更新,及时获取新特性和性能改进。
附录:版本兼容性参考
MyBatis版本 | MyBatis-Spring版本 | Spring版本要求 |
---|---|---|
3.5.x | 2.0.x | 5.0+ |
3.4.x | 1.3.x | 3.2.5+ |
3.3.x | 1.2.x | 3.2.2+ |
”`
注:本文实际字数约6500字,完整展示了从基础到高级的整合过程。在实际使用时,可根据具体项目需求调整配置细节。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。