美文网首页
SpringBoot整合Mybatis的几种常用使用方式

SpringBoot整合Mybatis的几种常用使用方式

作者: 爱做梦的锤子 | 来源:发表于2020-05-25 10:56 被阅读0次

SpringBoot 2.1.5.RELEASE
java version 1.8.0_231
mysql 5.7

一、工程添加数据库驱动和Mybatis依赖

<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <!--当前工程的pom继承了springboot的父pom,所以mysql驱动的版本号是继承父pom中mysql的版本号,在这里可以不写版本-->
</dependency>
<!--mybatis-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

二、配置文件写入数据源信息

  • 在application.yml中配置数据源信息,并使用hikri作为数据连接池
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dream_hammer_mall?characterEncoding=UTF-8&useSSL=false&useUnicode=true&serverTimezone=UTC
    username: root
    password: #你的数据库密码
    hikari:
      connection-timeout: 30000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
      minimum-idle: 5           #最小连接数
      maximum-pool-size: 20     #最大连接数
      auto-commit: true         #事务自动提交
      idle-timeout: 600000      #连接超时的最大时长(毫秒),超时则被释放(retired)
      pool-name: DataSourceHikariCP #连接池名称
      max-lifetime: 1800000     #连接生命时长,空闲未被使用超过最大时长则被释放
      connection-test-query: select 1

三、mybatis使用准备工作

  • 创建数据库表(这里使用演示表Student)

演示表名为student,有三个字段:id(主键),name(姓名),age(年龄)

CREATE TABLE
student
(
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(16),
    age INT,
    PRIMARY KEY (id)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci;
  • 编写实体类Student
public class Student {
    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() { return id; }

    public void setId(Integer id) { this.id = id; }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public Integer getAge() { return age; }

    public void setAge(Integer age) { this.age = age; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id) &&
                Objects.equals(name, student.name) &&
                Objects.equals(age, student.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}
  • 开启MapperScan注解

在SpringBoot的启动类上添加 org.mybatis.spring.annotation.MapperScan 这个注解

@SpringBootApplication
//MapperScan注解,开启Mapper扫描,扫描site.teamo.mall.dao包下所有mapper类
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

四、Mybatis常用使用方式

1.全注解方式

注解的方式可以完成基本的crud操作:@Insert,@Select,@Update,@Delete
优点:对于简单表和简单的sql业务使用起来比较方便,不需要去创建xml,修改配置文件等
缺点:复杂业务,使用这种方式,会使得代码看起来比较乱,而且这种方式,相当于将sql硬编码在代码中,如需对sql进行修改,需重新编译代码

@Component
@Mapper
public interface StudentDao1 {

    @Select("select * from student where id = #{id}")
    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "name", column = "name"),
            @Result(property = "age", column = "age")
    })
    Student selectOne(@Param("id") String studentId);

    /**
     * 当你的方法参数名和Sql参数名相同时,可以不使用@Param注解,
     * eg:
     *
     * @Select("select * from student where id = #{id}")
     * Student selectOne(String studentId);
     */


    @Insert("insert into student (id,name,age) values(#{id},#{name},#{age})")
    Integer insertOne(Student student);

    @Update("update student set name=#{name}, age=#{age} where id = #{id}")
    Integer updateOne(Student student);

    @Delete("delete from student where id = #{id}")
    Integer deleteOne(String id);
}

2.Provider注解+Java代码方式

这种方式是结合注解和Java代码的方式,使用@InsertProvider,@SelectProvider,@UpdateProvider,@DeleteProvider注解在方法上,在使用Java代码来拼装sql
优点:可以使用Java代码来编写多种判断逻辑,在Sql拼接的过程中可以根据数据进行多种操作,比如数据校验,数据格式转换,数据个性化设置(默认值)等
缺点:sql完全由代码拼接比较散乱,不便于管理,虽然可以根据数据进行多种校验操作,但是在设计上并不推荐把数据的业务逻辑放在拼装sql这一块,会使得代码比较杂乱

  • StudentDao代码
@Component
@Mapper
public interface StudentDao2 {

    @SelectProvider(type = StudentDao2Provider.class, method = "selectOne")
    Student selectOne(String studentId);

    @InsertProvider(type = StudentDao2Provider.class,method = "insertOne")
    Integer insertOne(Student student);

    @UpdateProvider(type = StudentDao2Provider.class,method = "updateOne")
    Integer updateOne(Student student);

    @DeleteProvider(type = StudentDao2Provider.class,method = "deleteOne")
    Integer deleteOne(String id);
}
  • Provider代码
public class StudentDao2Provider {
    public String selectOne(String id) {
        String sql = new SQL() {{
            SELECT("id,name,age");
            FROM("student");
            WHERE("id = #{id}");
        }}.toString();
        return sql;
    }

    public String insertOne(Student student) {
        String sql = new SQL() {{
            INSERT_INTO("student");
            if (student == null) {
                throw new RuntimeException("插入数据不能为空");
            }
            VALUES("id","#{id}");
            VALUES("name", "#{name}");
            //添加逻辑判断,如果age不合法,就设置默认15岁
            if (student.getAge() == null || student.getAge() > 100 || student.getAge() < 0) {
                VALUES("age","15");
            }else {
                VALUES("age", "#{age}");
            }
        }}.toString();
        return sql;
    }

    public String updateOne(Student student) {
        String sql = new SQL() {{
            UPDATE("student");
            if (student == null) {
                throw new RuntimeException("更新数据不能为空");
            }
            if (student.getName() != null) {
                SET("name=#{name}");
            }
            if (student.getAge() == null || student.getAge() > 100 || student.getAge() < 0) {
                throw new RuntimeException("学生年龄不能小于0大于100");
            }
            SET("age=#{age}");
            WHERE("id=#{id}");
        }}.toString();
        return sql;
    }

    public String deleteOne(String id) {
        String sql = new SQL() {{
            DELETE_FROM("student");
            WHERE("id=#{id}");
        }}.toString();
        return sql;
    }
}

3.xml方式

只需要定义接口,sql的编写和实体类的映射都在xml中配置
优点:sql自由度很高,都放在xml里便于统一管理和优化,同时代码比较简洁
缺点:简单的查询也需要修改xml,手写sql比较繁琐,同时由于sql自由度变高了,对sql了解不多的开发人员使用起来稍显困难

  • StudentDao代码
@Mapper
@Component
public interface StudentDao3 {

    Student selectOne(String studentId);

    Integer insertOne(Student student);

    Integer updateOne(Student student);

    Integer deleteOne(String id);
}
  • StudentDao.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="site.teamo.mall.dao.StudentDao3">
    <resultMap id="base_result_map" type="site.teamo.mall.bean.Student">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </resultMap>

    <select id="selectOne" resultMap="base_result_map" parameterType="java.lang.String">
        select * from student where id = #{id}
    </select>

    <insert id="insertOne" parameterType="site.teamo.mall.bean.Student">
        insert into student(id,name,age) values (#{id},#{name},#{age})
    </insert>

    <update id="updateOne" parameterType="site.teamo.mall.bean.Student">
        update student set name = #{name},age = #{age} where id = #{id}
    </update>

    <delete id="deleteOne" parameterType="java.lang.String">
        delete from student where id = #{id}
    </delete>
</mapper>

4.通用Mapper方式(xml+example)

java代码结合xml,简单的crud直接代码调用通用方法,复杂的业务sql使用xml便于管理和优化
优点:这种方式弥补了上述几种方式的不足,即实现了基本crud的通用方法,在简单查询时可以直接使用,也使用了xml配置可以统一管理,优化复杂sql,总体上是最推荐的一种mybatis使用方式
缺点:需要去实体类添加实体与数据库字段映射关系的注解

使用方式稍有不同,步骤如下

  • 在原有的基础上添加新pom依赖
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.1.5</version>
</dependency>
  • SpringBoot启动类上MapperScan进行更换,注释掉org下MapperScan换用tk包下的MapperScan
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//import org.mybatis.spring.annotation.MapperScan;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}
  • 在实体类上加上与数据资源映射的注解
public class Student {
    //使用通用Mapper时需要添加这些注解
    @Id
    private Integer id;
    @Column(name = "name")
    private String name;
    @Column(name = "age")
    private Integer age;

    public Integer getId() { return id; }

    public void setId(Integer id) { this.id = id; }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public Integer getAge() { return age; }

    public void setAge(Integer age) { this.age = age; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id) &&
                Objects.equals(name, student.name) &&
                Objects.equals(age, student.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}
  • StudentDao代码
@Component
public interface StudentDao4 extends Mapper<Student>, MySqlMapper<Student> {
    /**
     * 通用Mapper中有很多基础的crud方法,基本查询就可以使用通用Mapper中的方法
     * 当你有复杂的逻辑业务sql时,也可以自定义方法,如下就是自定义了一个演示方法
     */
    Student mySelectOne(String id);
}
  • StudentDao.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="site.teamo.mall.dao.StudentDao4">
    <resultMap id="base_result_map" type="site.teamo.mall.bean.Student">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </resultMap>

    <select id="mySelectOne" parameterType="java.lang.String" resultMap="base_result_map">
        select * from student where id =#{id}
    </select>
</mapper>

最后附上我的测试类

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import site.teamo.mall.bean.Student;
import site.teamo.mall.dao.StudentDao1;
import site.teamo.mall.dao.StudentDao2;
import site.teamo.mall.dao.StudentDao3;
import site.teamo.mall.dao.StudentDao4;

@RunWith(SpringRunner.class)
@SpringBootTest
@EnableAutoConfiguration
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class MybatisTest {

    @Autowired
    private StudentDao1 studentDao1;

    @Autowired
    private StudentDao2 studentDao2;

    @Autowired
    private StudentDao3 studentDao3;

    @Autowired
    private StudentDao4 studentDao4;

    @Test
    public void test1(){
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(20);
        Assert.assertEquals(1L,studentDao1.insertOne(student)*1L);
        Assert.assertEquals(student,studentDao1.selectOne("1"));
        student.setName("李四");
        Assert.assertEquals(1L,studentDao1.updateOne(student)*1L);
        Assert.assertEquals(student,studentDao1.selectOne("1"));
        Assert.assertEquals(1L,studentDao1.deleteOne("1")*1L);
    }

    @Test
    public void test2(){
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(20);
        Assert.assertEquals(1L,studentDao2.insertOne(student)*1L);
        Assert.assertEquals(student,studentDao2.selectOne("1"));
        student.setName("李四");
        Assert.assertEquals(1L,studentDao2.updateOne(student)*1L);
        Assert.assertEquals(student,studentDao2.selectOne("1"));
        Assert.assertEquals(1L,studentDao2.deleteOne("1")*1L);
    }

    @Test
    public void test3(){
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(20);
        Assert.assertEquals(1L,studentDao3.insertOne(student)*1L);
        Assert.assertEquals(student,studentDao3.selectOne("1"));
        student.setName("李四");
        Assert.assertEquals(1L,studentDao3.updateOne(student)*1L);
        Assert.assertEquals(student,studentDao3.selectOne("1"));
        Assert.assertEquals(1L,studentDao3.deleteOne("1")*1L);
    }

    @Test
    public void test4(){
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(20);
        Assert.assertEquals(1L,studentDao4.insert(student)*1L);
        Assert.assertEquals(student,studentDao4.selectByPrimaryKey("1"));
        student.setName("李四");
        Assert.assertEquals(1L,studentDao4.updateByPrimaryKey(student)*1L);
        Assert.assertEquals(student,studentDao4.mySelectOne("1"));
        Assert.assertEquals(1L,studentDao4.deleteByPrimaryKey(1)*1L);
    }
}

五、总结

  • hikriCP是SpringBoot的默认数据连接池,在日常工程中使用比较多的还有druid,druid是由阿里巴巴开源的一款数据连接池,两个数据连接池都比较优秀

  • mybatis的四种使用方式各有优缺点使用场景也不同

全注解方式,适合快速演示,或者简单表测试时使用,只要工程中有引入mybatis依赖既可以直接在代码中写sql使用
Provider注解加Java代码的方式,适合对sql不是很了解的开发人员使用,或者时sql的生成跟业务数据关联性比较强的时候使用
接口加xml方式,适用于对sql比较了解,以及项目中sql全都需要严格管理的项目使用
通用mapper方式,这个是比较推荐的,项目中简单sql不强制统一管理的时候可以使用,对于复杂sql也可以进行管理

大家在使用的时候根据自己的需要选择就可以了,如果你觉得这些都不好,那么你也可以自己设计实现一个自己ORM框架

关注公众号【爱做梦的锤子】后台回复【java知识点】可下载我整理的完整版思维导图
文章欢迎转载,转载请注明出处,个人公众号【爱做梦的锤子】,全网同id,个站 http://te-amo.site,欢迎关注,里面会分享更多有用知识,还有我的私密照片

相关文章

网友评论

      本文标题:SpringBoot整合Mybatis的几种常用使用方式

      本文链接:https://www.haomeiwen.com/subject/xxoeahtx.html