Spring Boot 整合Mybatis

在Mybatis初期 需要配置实体类、 配置映射文件 、DAO层代码等一大堆配置. 当然Mybatis 为了解决这些弊端开发了generator 可以根据数据库-数据表自动生成实体类、配置文件和dao层代码,减轻了一部分开发量. MyBatis还提供了注解的方式,适用于小型项目,不用在写配置文件,但是需要在注解上写SQL语句不利于管理. Spring Boot 化繁为简提供了mybatis-spring-boot-starter 可以轻松配置上手.

mybatis-spring-boot-starter 是Mybatis 整合Spring Boot的一套解决方案. 官方的:MyBatis Spring-Boot-Starter will help you use MyBatis with Spring Boot. 官方地址

  1. 首先构建一个Spring Web的Spring Boot项目. 在pom文件中,引入mybatis-spring-boot-starter 依赖包括mysql驱动.spring-boot-starter-web 引入的spring-mvc的依赖实现restful.
<!-- mybatis整合springboot的依赖 -->
     <dependency>
         <groupId>org.mybatis.spring.boot</groupId>
         <artifactId>mybatis-spring-boot-starter</artifactId>
         <version>2.1.0</version>
     </dependency>
 			<dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <!-- 引入mysql驱动依赖 -->
     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.19</version>
     </dependency>
  1. 在application.yml中配置,端口信息 数据源信息以及mybatis的配置(配置pojo实体类所在的包路径)
server:
      port: 8089
      tomcat:
        uri-encoding: UTF-8
    
    
    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/foodie-shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
        username: root
        password: root
    
    
    mybatis:
      type-aliases-package: com.prim.demo.t_spring_boot_mybatis.pojo #配置pojo所在包的路径

Spring Boot 会自动加载spring.datasource.* 的数据源配置,并且会自动注入到SqlSessionFactory中.

如果你还不理解,看一看原始的MyBatis加载配置操作,通过SqlSessionFactoryBuilder加载配置,Spring Boot帮助我们大大简化了操作,只需要关注配置文件的维护,Spring Boot内部已经自动加载注入到SqlSessionFactory中了.

private static SqlSessionFactory sqlSessionFactory = null;
    static {
        try {
            //加载xml配置文件
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            //得到SqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError(e);
        }
    }

    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * 设置SQL是否自动提交事务,一般对于数据库的写操作:插入 更新 删除 都需要手动提交事务来保证数据的完整性
     * @param isAutoCommit
     * @return
     */
    public static SqlSession openSession(boolean isAutoCommit){
        //默认情况下自动提交事务
        //false 关闭自动提交 需要手动提交事务
        return sqlSessionFactory.openSession(isAutoCommit);
    }

    public static void closeSession(SqlSession sqlSession){
        if (sqlSession != null){
            sqlSession.close();
        }
    }

在启动类中添加对Mapper包的扫描注解@MapperScan

@SpringBootApplication
@MapperScan(basePackages = "com.prim.demo.t_spring_boot_mybatis.mapper") 
//扫描mapper 或者在每个Mapper类上加入@Mapper注解不推荐这样使用推荐直接配置包名
public class TSpringBootMybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(TSpringBootMybatisApplication.class, args);
    }
}

通过配置mapper包,SpringBoot 会自动将mapper注入到SqlSession中,并且我们在使用时可直接获得实体对象调用.类似原始的方法:

<!-- 采用注解方式 两种方式为了更好的进行维护建议采用package的方式 -->
    <mappers>
<!--        <mapper class="com.prim.dao.GoodsDAO"/>-->
        <package name="com.prim.dao"/>
    </mappers>

public void selectDao(){
        SqlSession sqlSession = null;
        try {
            sqlSession = com.prim.utils.MyBatisUtils.openSession();
            GoodsDAO mapper = sqlSession.getMapper(GoodsDAO.class);
            List<Goods> list = mapper.selectPriceRange(100, 500, 20);
            System.out.println(list.size());
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            com.prim.utils.MyBatisUtils.closeSession(sqlSession);
        }
    }

在Spring Boot中将这些操作,全部在内部处理了,只需通过注入Mapper即可使用.

使用注解的方式

Mapper类,通过注解的方式输入SQL语句

public interface StuMapper {

    @Insert("INSERT INTO stu(name,age) VALUES(#{name},#{age})")
    void save(Stu stu);

    @Update("UPDATE stu SET name=#{name},age=#{age} where id=#{id}")
    void update(Stu stu);

    @Results(id = "resultMap", value = {
            @Result(property = "id", column = "id", id = true),
            @Result(property = "name", column = "name"),
            @Result(property = "age", column = "age")
    })
    @Select("SELECT * FROM stu WHERE id=#{id}")
    Stu selectOne(int id);

    @ResultMap("resultMap")
    @Select("SELECT * FROM stu")
    List<Stu> selectAll();

    @Delete("DELETE FROM stu WHERE id=#{id}")
    void delete(int id);
}
  • @Select 查询类的注解,所有的查询操作
  • @Results 修饰返回的结果集,关联实体类属性和数据库中的字段,可通过设置id,其他方法的查询结果集可以复用
  • @Insert 插入数据操作
  • @Update 修改数据操作
  • @Delete 删除数据操作

注意:一定要使用#符号不要使用\(符号,因为\)符号有SQL注入攻击的漏洞

符号类似:SELECT * FROM stu WHERE id=?

$符号类似:SELECT * FROM stu WHERE id='id'

构建业务成Service,@Service 注入业务类,通过@Autowired注入mapper对象

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;

    @Override
    public void save() {
        Stu stu = new Stu();
        stu.setName("test-1");
        stu.setAge(32);
        stuMapper.save(stu);
    }

    @Override
    public void update(int id) {
        Stu stu = new Stu();
        stu.setId(id);
        stu.setName("update-1");
        stu.setAge(28);
        stuMapper.update(stu);
    }

    @Override
    public void delete(int id) {
        stuMapper.delete(id);
    }

    @Override
    public Stu getOne(int id) {
        return stuMapper.selectOne(id);
    }

    @Override
    public List<Stu> getAll() {
        return stuMapper.selectAll();
    }
}

在api层也就是controller层使用

@RestController
public class TestController {

    @Autowired
    private StuService stuService;

    @GetMapping("/getStu")
    public Object getStu(int id) {
        return stuService.getOne(id);
    }

    @PostMapping("/add")
    public Object addStu() {
        stuService.save();
        return "保存 ok";
    }

    @PostMapping("/update")
    public Object updateStu(int id) {
        stuService.update(id);
        return "更新 ok";
    }

    @PostMapping("/delete")
    public Object deleteStu(int id) {
        stuService.delete(id);
        return "删除 ok";
    }
}

极简XML方式

通过XML的方式,不需要在Java类中通过注解写SQL语句,而是和Java代码分离,通过XML的方式映射文件,mapper只需要定义空方法即可

  1. 配置mybatis的xml方式 在application.yml中配置映射文件路径和mybatis的配置文件路径,Spring Boot会自动装配这些配置
mybatis:
      type-aliases-package: com.prim.demo.t_spring_boot_mybatis.pojo #配置pojo所在包的路径
      mapper-locations: classpath:mapper/*.xml                       #映射文件的路径
      config-location: classpath:mybatis/mybatis-config.xml          #mybatis配置文
  1. 配置映射文件 其实就是将注解中的SQL移到映射文件中
insert into stu(name, age)
         values (#{name}, #{age})
     
         update stu
         set name=#{name},
             age=#{age}
         where id = #{id}
     
         delete
         from stu
         where id = #{id}
     
         select *
         from stu
     
         SELECT *
         FROM stu
         WHERE id = #{id}

mybatis-config.xml 配置,主要配置了一些基础的信息,比如类名的简化等,这样在映射文件中的parameterType="java.lang.Integer" 不用这样写了 直接写parameterType="Integer"

<?xml version="1.0" encoding="utf-8" ?>
<!-- mybatis 的文档约束 -->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer"/>
        <typeAlias alias="Long" type="java.lang.Long"/>
        <typeAlias alias="HashMap" type="java.util.HashMap"/>
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
        <typeAlias alias="ArrayList" type="java.util.ArrayList"/>
        <typeAlias alias="LinkedList" type="java.util.LinkedList"/>
    </typeAliases>
</configuration>

Mapper层的代码方法名只要和映射文件中的id一一对应即可

public interface StuMapper {

    void save(Stu stu);

    void update(Stu stu);

   
    Stu selectOne(int id);


    List<Stu> selectAll();

    void delete(int id);
}

至于service层和controller层的代码不用修改.

如何选择呢?

一般在项目中,注解方式适合简单快速的项目.xml方式更加适合大型项目方便管理.实际项目中根据实际情况来选择.

示例代码