SpringBoot 整合 Mybatis 实现数据表增删改查,保姆级教程!

开发 前端
本文主要围绕利用 Mybatis 框架来实现对数据库表的快速访问操作,与 Spring Boot JPA 相比,Mybatis 在使用上更加灵活,对数据表的操作就像在本地数据库写 SQL 一样方便,对于业务复杂的查询场景,它比 Spring Boot JPA 要灵活很多。

01、背景介绍

在上一篇文章中,我们介绍了利用 Spring Boot JPA 来实现对数据库的访问操作,虽然它在国外广泛流行,但是在国内流行程度远不如 MyBatis。

原因在于,在 ORM 框架中其实还有另一个翘楚,那就是刚刚说到的 MyBatis,它的实现方式与 Spring Boot JPA 完全不同,MyBatis 框架不会帮助用户动态生成 SQL 语句,它把 SQL 的编写工作完全交给了用户,开发者可以像在本地数据库中写 SQL 语句一样快速的完成对数据库表的操作,非常易于新人上手,唯一的缺点就是配置工作量很大,好在有代码生成器,可以帮助开发者减轻不少的开发工作量。

ORM 框架发展至今,只剩下两家了,一个是以Hibernate为代表,开发者可以不用写一句 SQL 就可以轻松完成对数据库的访问操作;另一个是以MyBatis为代表,开发者可以根据自己的业务需求灵活的编写动态 SQL 完成对数据库的访问操作。

总的来说,两者各有特点,如果当前业务所有的业务操作都是单表并且没有很复杂的查询要求,那么采用 Spring Boot JPA 来开发,效率会更高;如果业务很复杂,各表之间经常需要连表查询,那么采用MyBatis来开发会是一个非常好的选择。在企业级系统开发中,因为业务比较复杂,国内采用MyBatis来开发的项目相对比较多些。

今天这篇文章我们就具体来说说如何在 Spring Boot 中整合 MyBatis 完成数据库表的增删改查操作。

02、应用实践

2.1、工程配置

首先,在pom.xml文件中引入mybatis-spring-boot-starter依赖,具体如下:

<!--spring boot mybatis支持-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<!--mysql 驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

关于mybatis-spring-boot-starter与Spring Boot的版本对应关系,可以参考如下:

  • 1.3.x版本:适用于 MyBatis 3.4+、Java 6+、Spring Boot 1.5
  • 2.0.x版本:适用于 MyBatis 3.5+、Java 8+、Spring Boot 2.0/2.1
  • 2.1.x版本:适用于 MyBatis 3.5+、Java 8+、Spring Boot 2.1+

本项目采用的是Spring Boot 2.1.0构建,因此选择2.0.0版本。

然后,在application.properties文件中添加数据源信息和相关的MyBatis配置参数,内容如下:

# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# 打印SQL语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

MyBatis支持两种开发模式。

  • 第一种:基于注解的配置实现
  • 第二种:基于XML的配置实现

下面我们一起来这两种具体的应用方式。

2.2、基于注解的配置实现

基于注解的配置实现,简单的说就是采用注解来开发,具体实现如下。

2.2.1、创建数据库表

首先,mybatis框架不会帮助我们根据实体类自动生成目标数据库表,因此我们需要事先设计好数据库表结构,在此我们以角色表tb_role为例,具体创建命令如下。

CREATE TABLE `tb_role` (
  `id` int(11) unsigned NOT NULL COMMENT '主键ID',
  `role_name` varchar(50) DEFAULT NULL COMMENT '角色名称',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.2.2、编写对应的实体类

package com.example.springboot.entity;

public class Role {

    /**
     * 主键ID
     */
    private Integer id;

    /**
     * 角色名称
     */
    private String roleName;

    /**
     * 创建时间
     */
    private Date createTime;

    // set、get方法等...
}

2.2.3、编写对应的 Mapper 接口

package com.example.springboot.mapper;

public interface RoleMapper {

    @Select("select * from tb_role")
    @Results({
            @Result(property = "id",  column = "id"),
            @Result(property = "roleName",  column = "role_name"),
            @Result(property = "createTime", column = "create_time")
    })
    List<Role> findAll();

    @Select("select * from tb_role where id =#{id}")
    @Results({
            @Result(property = "id",  column = "id"),
            @Result(property = "roleName",  column = "role_name"),
            @Result(property = "createTime", column = "create_time")
    })
    Role findById(@Param("id") Integer id);

    @Insert("insert into tb_role(id, role_name, create_time) VALUES(#{id}, #{roleName}, #{createTime})")
    int insert(Role role);

    @Update("update tb_role set role_name=#{roleName} WHERE id=#{id}")
    int update(Role role);

    @Delete("delete from tb_role where id =#{id}")
    int delete(@Param("id") Integer id);
}

2.2.4、添加 Mapper 接口扫描路径

默认创建的 Mapper 接口无法被自动加载到 Spring IOC 容器中,因此需要在Application启动类上,添加 Mapper 接口的包扫描路径,可以通过@MapperScan注解来完成注入,具体如下。

@MapperScan("com.example.springboot.mapper")
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2.2.5、单元测试

最后,我们编写单元测试来验证一下内容的正确性,代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class RoleMapperJunit {

    @Autowired
    private RoleMapper roleMapper;

    @Test
    public void test(){
        // 新增数据
        roleMapper.insert(new Role(1, "开发工程师", new Date()));
        roleMapper.insert(new Role(2, "测试工程师", new Date()));
        roleMapper.insert(new Role(3, "项目经理", new Date()));

        // 查询数据
        List<Role> roleList = roleMapper.findAll();
        System.out.println("第一次查询全部数据结果:" + roleList.toString());

        System.out.println("----------------------");

        // 修改单条数据
        roleMapper.update(new Role(1, "技术经理"));

        // 单条查询
        Role role = roleMapper.findById(1);
        System.out.println("查询[id=1]结果:" + role.toString());

        System.out.println("----------------------");

        // 删除单条数据
        roleMapper.delete(1);

        // 查询数据
        List<Role> roleList1 = roleMapper.findAll();
        System.out.println("第二次查询全部数据结果:" + roleList1.toString());
    }
}

运行单元测试,输出结果如下!

第一次查询全部数据结果:[Role{id=1, roleName='开发工程师', createTime=Sun Apr 28 11:44:52 CST 2024}, Role{id=2, roleName='测试工程师', createTime=Sun Apr 28 11:44:52 CST 2024}, Role{id=3, roleName='项目经理', createTime=Sun Apr 28 11:44:52 CST 2024}]
----------------------
查询[id=1]结果:Role{id=1, roleName='技术经理', createTime=Sun Apr 28 11:44:52 CST 2024}
----------------------
第二次查询全部数据结果:[Role{id=2, roleName='测试工程师', createTime=Sun Apr 28 11:44:52 CST 2024}, Role{id=3, roleName='项目经理', createTime=Sun Apr 28 11:44:52 CST 2024}]

至此,基于注解模式的实现方式已经介绍完毕了。

如果有一定开发经历的同学可能会感觉到,基于注解方式的开发模式虽然简单,但是弊端也很大,假如查询的时候,需要连接的表很多,字段也多,代码可读性就变得很差,因此大多数情况下,开发者会更倾向于选择基于 XML 的配置实现方式开发,原因是它的可读性更高。

2.3、基于XML的配置实现

基于 XML 的配置实现,是一种最常用的开发模式,具体实现如下。

2.3.1、创建数据库表

与上面类似,我们创建一张新表tb_menu来介绍,具体创建命令如下。

CREATE TABLE `tb_menu` (
  `id` int(11) unsigned NOT NULL COMMENT '主键ID',
  `menu_name` varchar(50) DEFAULT NULL COMMENT '菜单名称',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.3.2、编写对应的实体类

package com.example.springboot.entity;

public class Menu {

    /**
     * 主键ID
     */
    private Integer id;

    /**
     * 菜单名称
     */
    private String menuName;

    /**
     * 创建时间
     */
    private Date createTime;

    // set、get方法等...
}

2.3.3、编写对应的 Mapper 接口

与上面基于注解的开发模式类似,只是少了注解配置。

package com.example.springboot.mapper;

public interface MenuMapper {

    List<Menu> findAll();

    Menu findById(@Param("id") Integer id);

    int insert(Menu role);

    int update(Menu role);

    int delete(@Param("id") Integer id);
}

2.3.4、创建 XML 映射文件

在src/main/resources/mybatis/mapper目录下创建MenuMapper.xml文件,并与 Mapper 接口建立映射关系,内容如下:

<?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.springboot.mapper.MenuMapper">

    <!--BaseResultMap-->
    <resultMap id="BaseResultMap" type="com.example.springboot.entity.Menu" >
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="menu_name" property="menuName" jdbcType="VARCHAR" />
        <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
    </resultMap>

    <!--Base_Column_List-->
    <sql id="Base_Column_List">
        id
        ,menu_name
        ,create_time
    </sql>

    <select id="findAll" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from tb_menu
        order by id
    </select>

    <select id="findById" resultMap="BaseResultMap" parameterType="java.lang.Integer">
        select
        <include refid="Base_Column_List"/>
        from tb_menu
        where id = #{id,jdbcType=INTEGER}
    </select>

    <insert id="insert" parameterType="com.example.springboot.entity.Menu">
        insert into tb_menu(id, menu_name, create_time)
        values(#{id}, #{menuName}, #{createTime})
    </insert>

    <update id="update" parameterType="com.example.springboot.entity.Menu">
        update tb_menu
        set menu_name = #{menuName,jdbcType=VARCHAR}
        where id = #{id,jdbcType=INTEGER}
    </update>

    <delete id="delete" parameterType="java.lang.Integer">
        delete from tb_menu
        where id = #{id,jdbcType=INTEGER}
    </delete>

</mapper>

2.3.5、创建 Mybatis 全局配置文件

在src/main/resources/mybatis目录下创建mybatis-config.xml文件,可以全局配置 mybatis 相关属性信息,示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- 指定MyBatis所用日志的具体实现,STDOUT_LOGGING:表示打印到控制台-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>

    <typeAliases>
        <!--配置类型别名可为Java类型设置一个缩写名字,以便于在xml中通过简写来代替全限定类名-->
        <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>

更多的配置属性,可以参考这篇文章。

2.3.6、添加 Mapper 接口扫描路径

同上,需要在Application启动类上添加 Mapper 接口的包扫描路径,如果已添加,可以忽略。

@MapperScan("com.example.springboot.mapper")
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2.3.7、配置 XML 文件扫描路径

与基于注解的开发模式稍有不同,我们还需要在application.properties文件中配置 Mybatis 相关的 XML 文件扫描目录,否则启动报错,内容如下:

# 配置mybatis全局配置文件扫描
mybatis.config-location=classpath:mybatis/mybatis-config.xml
# 配置mybatis的xml配置文件扫描目录
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
# 打印SQL语句,需要注射掉这个mybatis全局属性配置,否则启动报错
#mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.3.8、单元测试

最后,我们编写单元测试来验证一下内容的正确性,代码如下:

public class MenuMapperJunit {

    @Autowired
    private MenuMapper menuMapper;

    @Test
    public void test(){
        // 新增数据
        menuMapper.insert(new Menu(1, "用户菜单", new Date()));
        menuMapper.insert(new Menu(2, "角色菜单", new Date()));
        menuMapper.insert(new Menu(3, "系统菜单", new Date()));

        // 查询数据
        List<Menu> menuList = menuMapper.findAll();
        System.out.println("第一次查询全部数据结果:" + menuList.toString());

        System.out.println("----------------------");

        // 修改单条数据
        menuMapper.update(new Menu(1, "项目菜单"));

        // 单条查询
        Menu menu = menuMapper.findById(1);
        System.out.println("查询[id=1]结果:" + menu.toString());

        System.out.println("----------------------");

        // 删除单条数据
        menuMapper.delete(1);

        // 查询数据
        List<Menu> menuList1 = menuMapper.findAll();
        System.out.println("第二次查询全部数据结果:" + menuList1.toString());
    }
}

运行单元测试,输出结果如下!

第一次查询全部数据结果:[Menu{id=1, menuName='用户菜单', createTime=Sun Apr 28 14:24:49 CST 2024}, Menu{id=2, menuName='角色菜单', createTime=Sun Apr 28 14:24:49 CST 2024}, Menu{id=3, menuName='系统菜单', createTime=Sun Apr 28 14:24:50 CST 2024}]
----------------------
查询[id=1]结果:Menu{id=1, menuName='项目菜单', createTime=Sun Apr 28 14:24:49 CST 2024}
----------------------
第二次查询全部数据结果:[Menu{id=2, menuName='角色菜单', createTime=Sun Apr 28 14:24:49 CST 2024}, Menu{id=3, menuName='系统菜单', createTime=Sun Apr 28 14:24:50 CST 2024}]

至此,基于 XML 模式的实现方式已经介绍完毕了。

实际开发过程中,如果不需要自定义全局配置 Mybatis 数据,也可以省掉创建 Mybatis 全局配置文件这一步。

03、小结

本文主要围绕利用 Mybatis 框架来实现对数据库表的快速访问操作,与 Spring Boot JPA 相比,Mybatis 在使用上更加灵活,对数据表的操作就像在本地数据库写 SQL 一样方便,对于业务复杂的查询场景,它比 Spring Boot JPA 要灵活很多。而且可维护性更高。

如果是企业级的 web 项目,推荐采用 Mybatis 框架作为持久层。

04、参考

  1. https://mybatis.net.cn/
责任编辑:武晓燕 来源: 潘志的研发笔记
相关推荐

2024-08-29 08:58:30

JPA编写数据操

2021-10-20 09:04:21

Spring Beanscope数据库

2020-05-28 16:50:59

源码分析 MybatisJava

2012-04-19 10:06:16

ibmdw

2019-11-07 15:39:36

数据库MySQL文章

2021-07-05 09:24:06

MySQL SQL 语句数据库

2023-02-27 07:37:56

Curl操作SQL

2012-04-12 09:23:15

达梦数据库

2024-11-18 00:22:34

2009-11-13 15:54:26

ADO.NET数据库操

2023-06-08 08:13:43

2023-06-07 08:08:37

MybatisSpringBoot

2022-12-12 11:47:34

WindowsPySpark服务器

2022-12-01 11:41:24

2024-07-26 10:50:51

SpringScrew数据库

2022-04-28 07:31:41

Springkafka数据量

2020-10-29 08:39:45

JSONJava对象

2021-05-19 09:53:16

SpringbootMyBatisMySQL

2024-07-24 20:01:03

2023-07-06 09:01:33

点赞
收藏

51CTO技术栈公众号