Spring Boot集成MyBatis的优点包括简化配置,通过自动配置和起步依赖快速搭建项目,提供灵活的SQL编写方式,支持XML注解两种形式,便于复杂查询优化;与Spring生态无缝整合,利用事务管理、依赖注入等特性;轻量级且高性能,减少手动JDBC样板代码。
1、环境准备
创建SpringBoot项目
首先使用Spring Initializr创建一个新的Spring Boot项目,选择以下依赖:
- Spring Web
- MyBatis Framework
- MySQL Driver (或其他你需要的数据库驱动)
或者直接在pom.xml中添加依赖:
xml
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Spring Boot Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok (可选,简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
数据库配置
在application.properties或application.yml中配置数据库连接信息:
yml
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# MyBatis配置
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.demo.entity
# 开启驼峰命名转换
mybatis.configuration.map-underscore-to-camel-case=true
2、项目结构
标准的项目结构如下(大家可以根据自己的情况来调整):
src/main/java
├── com.example.demo
│ ├── DemoApplication.java
│ ├── controller
│ ├── service
│ ├── dao/mapper
│ └── entity
src/main/resources
├── application.properties
└── mapper
3、基础集成
创建实体类
java
@Data
public class User {
private Long id;
private String username;
private String password;
private String email;
// 省略getter/setter,使用了lombok的@Data注解
}
创建Mapper接口
java
@Mapper // 标识这是一个MyBatis的Mapper接口
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);
@Select("SELECT * FROM user")
List<User> findAll();
@Insert("INSERT INTO user(username, password, email) VALUES(#{username}, #{password}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id") // 获取自增主键
int insert(User user);
@Update("UPDATE user SET username=#{username}, password=#{password}, email=#{email} WHERE id=#{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id=#{id}")
int delete(Long id);
}
创建Service层
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User findById(Long id) {
return userMapper.findById(id);
}
public List<User> findAll() {
return userMapper.findAll();
}
public int insert(User user) {
return userMapper.insert(user);
}
public int update(User user) {
return userMapper.update(user);
}
public int delete(Long id) {
return userMapper.delete(id);
}
}
创建Controller
java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User findById(@PathVariable Long id) {
return userService.findById(id);
}
@GetMapping
public List<User> findAll() {
return userService.findAll();
}
@PostMapping
public String insert(@RequestBody User user) {
userService.insert(user);
return "Insert success";
}
@PutMapping
public String update(@RequestBody User user) {
userService.update(user);
return "Update success";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Long id) {
userService.delete(id);
return "Delete success";
}
}
4、XML方式配置SQL
虽然但是哈哈哈哈,注解方式简单,但复杂SQL还是推荐使用XML配置方式~
修改Mapper接口
java
@Mapper
public interface UserMapper {
User findById(Long id);
List<User> findAll();
int insert(User user);
int update(User user);
int delete(Long id);
}
创建XML映射文件
在resources/mapper目录下创建UserMapper.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.example.demo.entity.User">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
<result column="email" property="email" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
id, username, password, email
</sql>
<select id="findById" parameterType="java.lang.Long" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM user
WHERE id = #{id}
</select>
<select id="findAll" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM user
</select>
<insert id="insert" parameterType="com.example.demo.entity.User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(username, password, email)
VALUES(#{username}, #{password}, #{email})
</insert>
<update id="update" parameterType="com.example.demo.entity.User">
UPDATE user
SET username = #{username},
password = #{password},
email = #{email}
WHERE id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Long">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
5、高级功能
动态SQL
MyBatis提供了强大的动态SQL功能:
xml
<select id="findByCondition" parameterType="map" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM user
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>
对应的Mapper接口:
java
List<User> findByCondition(@Param("username") String username, @Param("email") String email);
分页查询
Spring Boot集成MyBatis分页有多种方式,这里介绍使用PageHelper:
xml
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
使用:
java
@GetMapping("/page")
public PageInfo<User> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users = userService.findAll();
return new PageInfo<>(users);
}
多数据源配置
当需要连接多个数据库时:
# 主数据源
spring.datasource.primary.url=jdbc:mysql://localhost:3306/db1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
# 次数据源
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/db2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
配置类
java
@Configuration
@MapperScan(basePackages = "com.example.demo.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate")
public class PrimaryDataSourceConfig {
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
@Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "primarySqlSessionFactory")
@Primary
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();
}
@Bean(name = "primaryTransactionManager")
@Primary
public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "primarySqlSessionTemplate")
@Primary
public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
// 类似配置次数据源
@Configuration
@MapperScan(basePackages = "com.example.demo.mapper.secondary", sqlSessionTemplateRef = "secondarySqlSessionTemplate")
public class SecondaryDataSourceConfig {
// 类似上面的配置,去掉@Primary注解
}
6、事务管理
Spring Boot已经集成了事务管理,只需在Service方法上添加@Transactional注解:
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
User fromUser = userMapper.findById(fromId);
User toUser = userMapper.findById(toId);
fromUser.setBalance(fromUser.getBalance().subtract(amount));
toUser.setBalance(toUser.getBalance().add(amount));
userMapper.update(fromUser);
// 模拟异常
// int i = 1 / 0;
userMapper.update(toUser);
}
}
7、常见问题解决
- Mapper接口无法注入
- 确保添加了
@Mapper注解或在启动类上添加@MapperScan - 检查包路径是否正确
- 确保添加了
- XML文件无法加载
- 检查
mybatis.mapper-locations配置 - 确保XML文件在resources目录下正确位置
- 检查
- 驼峰命名转换无效
- 检查
mybatis.configuration.map-underscore-to-camel-case=true配置 - 或者在XML中使用
resultMap手动映射
- 检查
- 事务不生效
- 确保方法是public的
- 确保异常被抛出而不是被捕获
- 确保调用的方法来自另一个类(自调用问题)
8、最佳实践
- 分层清晰:严格遵循Controller-Service-Dao分层
- SQL优化:复杂查询使用XML配置,简单查询使用注解
- 事务粒度:事务应放在Service层,保持粒度适中
- 异常处理:统一异常处理,不要吞没异常
- 日志记录:添加MyBatis SQL日志方便调试