7、集成MyBatis

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.propertiesapplication.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、常见问题解决

  1. Mapper接口无法注入
    • 确保添加了@Mapper注解或在启动类上添加@MapperScan
    • 检查包路径是否正确
  2. XML文件无法加载
    • 检查mybatis.mapper-locations配置
    • 确保XML文件在resources目录下正确位置
  3. 驼峰命名转换无效
    • 检查mybatis.configuration.map-underscore-to-camel-case=true配置
    • 或者在XML中使用resultMap手动映射
  4. 事务不生效
    • 确保方法是public的
    • 确保异常被抛出而不是被捕获
    • 确保调用的方法来自另一个类(自调用问题)

8、最佳实践

  1. 分层清晰:严格遵循Controller-Service-Dao分层
  2. SQL优化:复杂查询使用XML配置,简单查询使用注解
  3. 事务粒度:事务应放在Service层,保持粒度适中
  4. 异常处理:统一异常处理,不要吞没异常
  5. 日志记录:添加MyBatis SQL日志方便调试
相关推荐
香吧香3 小时前
Spring boot 中 CommandLineRunner 在服务启动完成后自定义执行
java·spring boot·spring cloud
一 乐3 小时前
美食推荐|基于springboot+vue的美食分享系统设计与实现(源码+数据库+文档)
前端·数据库·vue.js·spring boot·后端·美食
2501_916766543 小时前
【Mybatis】注解开发与事务
mybatis
qq_12498707533 小时前
基于springboot+vue+mysql的校园博客系统(源码+论文+部署+安装)
java·vue.js·spring boot·mysql·毕业设计
韩立学长4 小时前
基于Springboot民族文化与旅游网站j9x74dt2(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
是梦终空4 小时前
计算机毕业设计248—基于Java+Springboot+vue的博物馆预约系统(源代码+数据库+开发文档)
java·spring boot·vue·毕业设计·jwt·博物馆预约系统·博物馆网站
少年攻城狮4 小时前
Mybatis-Plus系列---【自定义拦截器实现sql完整拼接及耗时打印】
数据库·sql·mybatis
7哥♡ۣۖᝰꫛꫀꪝۣℋ5 小时前
Spring Boot ⽇志
java·spring boot·后端
清晓粼溪5 小时前
Mybatis02:核心功能
java·mybatis