3.1 Spring Boot 集成 MyBatis

通过 SpringBoot +MyBatis 实现对数据库学生表的查询操作

3.1.1 案例思路

1、添加依赖(Mybatis、连接数据库的驱动)

2、连接数据库的配置

3、通过Mabatis逆向工程生成:数据持久层和实体Bean

3.1.2 实现步骤

(1) 准备数据库
1、通过idea本身的工具连接本地Mysql数据库

点击在最右侧这个按钮:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_java

创建连接:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_mybatis_02

Name:随便取,作为连接名

Host:因为连接的是本地的数据库,所以直接localhost,端口号默认3306

User:自己在配置数据库或者闲暇的时候创建的用户

Password:用户的密码

URL:默认写有,不过最好加一个参数serverTimezone=UTC,不然胡子哎Test Connection时极大概率出现时区的报错

2、创建新的数据库 springboot并向表中添加数据
create  database springboot;
create table t_student 
(
   id                   int(10)                        not null auto_increment,
   stu_name                 varchar(20)                    null,
   stu_age                  int(10)                        null,
   constraint PK_T_STUDENT primary key clustered (id)
);

insert into t_student(stu_name,stu_age) values("zhangsan",25);
insert into t_student(stu_name,stu_age) values("lisi",28);
insert into t_student(stu_name,stu_age) values("wangwu",23);
insert into t_student(stu_name,stu_age) values("Tom",21);
insert into t_student(stu_name,stu_age) values("Jck",55);
insert into t_student(stu_name,stu_age) values("Lucy",27);
insert into t_student(stu_name,stu_age) values("zhaoliu",75);
3、创建完成

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_mysql_03

(2)实现Mybatis逆向生成
1、GeneratorMapper.xml文件

先在项目根目录下创建GeneratorMapper.xml文件,用于指定Mybatis逆向生成的相关配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!--上面会报红,不过不要紧,实际是指涉及一个dto的配置-->

<generatorConfiguration>

    <!-- 指定连接数据库的 JDBC 驱动包所在位置,指定到你本机的完整路径 -->
    <classPathEntry location="C:\Users\15998\.m2\repository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar"/>

    <!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->
    <context id="tables" targetRuntime="MyBatis3">

        <!-- 抑制生成注释器,因为生成的注释都是英文的,可以不让它生成 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 配置数据库连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/springboot"
                        userId="root"
                        password="qks218126">
        </jdbcConnection>

        <!-- 生成 model 类,targetPackage 指定 model 类的包名, targetProject 指定
       生成的 model 放在 eclipse 的哪个工程下面-->
        <javaModelGenerator targetPackage="com.example.springbootworkspace.model"
                            targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="false" />
        </javaModelGenerator>

        <!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage 指定 mapper.xml 文件的
       包名, targetProject 指定生成的 mapper.xml 放在 eclipse 的哪个工程下面 -->
        <sqlMapGenerator targetPackage="com.example.springbootworkspace.mapper"
                         targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

        <!-- 生成 MyBatis 的 Mapper 接口类文件,targetPackage 指定 Mapper 接口类的包
       名, targetProject 指定生成的 Mapper 接口放在 eclipse 的哪个工程下面 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.example.springbootworkspace.mapper"
                             targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 数据库表名及对应的 Java 模型类名 -->
        <table tableName="t_student" domainObjectName="Student"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false"/>
    </context>
</generatorConfiguration>
2、添加Mysql反向工程依赖

注意别放错位置

<!--mybatis 代码自动生成插件-->
<plugin>
     <groupId>org.mybatis.generator</groupId>
     <artifactId>mybatis-generator-maven-plugin</artifactId>
     <version>1.3.6</version>
     <configuration>
         
     <!--配置文件的位置-->
     <configurationFile>GeneratorMapper.xml</configurationFile>
     <verbose>true</verbose>
     <overwrite>true</overwrite>
     </configuration>
</plugin>
3、生成实体类和映射文件

点开Maven配置,找到图中蓝色的那个东东,双击:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_java_04

成功生成:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_spring_05

生成的实体Bean和数据持久层以及映射文件:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_java_06

4、生成的代码

实体类

public class Student {
    private Integer id;

    private String stuName;

    private Integer stuAge;

    public Integer getId() {
        return id;
    }

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

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public Integer getStuAge() {
        return stuAge;
    }

    public void setStuAge(Integer stuAge) {
        this.stuAge = stuAge;
    }
}

数据持久层接口

注意,原本是没有@Mapper注解的,需要我们手动添加

@Mapper
public interface StudentMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Student record);

    int insertSelective(Student record);

    Student selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Student record);

    int updateByPrimaryKey(Student record);
}

数据持久层的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.springbootworkspace.mapper.StudentMapper">

  <resultMap id="BaseResultMap" type="com.example.springbootworkspace.model.Student">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="stu_name" jdbcType="VARCHAR" property="stuName" />
    <result column="stu_age" jdbcType="INTEGER" property="stuAge" />
  </resultMap>

  <sql id="Base_Column_List">
    id, stu_name, stu_age
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from t_student
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from t_student
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.example.springbootworkspace.model.Student">
    insert into t_student (id, stu_name, stu_age
      )
    values (#{id,jdbcType=INTEGER}, #{stuName,jdbcType=VARCHAR}, #{stuAge,jdbcType=INTEGER}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.example.springbootworkspace.model.Student">
    insert into t_student
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="stuName != null">
        stu_name,
      </if>
      <if test="stuAge != null">
        stu_age,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="stuName != null">
        #{stuName,jdbcType=VARCHAR},
      </if>
      <if test="stuAge != null">
        #{stuAge,jdbcType=INTEGER},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.example.springbootworkspace.model.Student">
    update t_student
    <set>
      <if test="stuName != null">
        stu_name = #{stuName,jdbcType=VARCHAR},
      </if>
      <if test="stuAge != null">
        stu_age = #{stuAge,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.example.springbootworkspace.model.Student">
    update t_student
    set stu_name = #{stuName,jdbcType=VARCHAR},
      stu_age = #{stuAge,jdbcType=INTEGER}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>
(3) 在 pom.xml 中添加相关 jar 依赖
<!--MyBatis整合SpringBoot的起步依赖--> 
<dependency> 
    <groupId>org.mybatis.spring.boot</groupId> 
    <artifactId>mybatis-spring-boot-starter</artifactId> 
    <version>2.0.1</version> 
</dependency> 	
	 
<!--MySQL的驱动依赖--> 
<dependency> 
    <groupId>mysql</groupId> 
    <artifactId>mysql-connector-java</artifactId> 
</dependency>
(4) 在application.properties中配置数据源(连接数据库)

mysql8之后的class-name已经改为: com.mysql.cj.jdbc.Driver

要注意时区,可以设置成Asia/Shanghai

根据自己数据库的信息修改以下内容,需要改的就是url的地址,以及username和password

#配置内嵌Tomcat端口号 
server.port=9090 

#配置数据库的连接信息 
#注意这里的驱动类有变化 
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 
spring.datasource.username=root
spring.datasource.password=123456
(5)开发代码
1、控制层

在 web 包下创建 StudentController 并编写代码

@Controller 
public class StudentController { 

    @Autowired
    private StudentService studentService; 
     
    @RequestMapping(value = "/student/details")     
    public @ResponseBody Object student(Integer id) { 
        Student student = studentService.queryStudentById(id); 
        return student; 
    }
}
2、业务层

在service包下编写StudentService接口

编写方法queryStudentById,根据学生id获取学生信息

public interface StudentService {

    /*
    * 根据学生id获取学生详情
    * */

    Student queryStudentById(Integer id);
}

service包下创建一个Impl类,用于放置接口实现类

并在业务层里注入数据持久层接口

记得写@Service注解

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentMapper studentMapper;

    @Override
    public Student queryStudentById(Integer id) {
        //这里接收的参数就是前端传过来的参数
        return studentMapper.selectByPrimaryKey(id);
    }
}
注意
pom.xml的改动

StudentMapper.xml是Mybatis逆向工程生成的配置文件,注意这是配置文件(看.xml后缀),而Springboot对于配置文件的要求是要放在resources目录下,所以直接运行时会出现如下报错(这是因为没有找到配置文件的原因)

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.springbootworkspace.mapper.StudentMapper.selectByPrimaryKey

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_mybatis_07

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_spring boot_08

所以我们需要做出如下改动,在pom.xml文件中加入如下代码,指定资源文件:

<resource>
   <directory>src/main/java</directory>
   <includes>
      <include>**/*.xml</include>
   </includes>
</resource>

重新编译文件就可以看到它已经出现在target里面了:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_mybatis_09

此时还有一个需要注意的地方,如果pom指定了resources标签,那么他就只会去这个标签里面找子标签resource所指定的资源文件。

如果这个时候恰巧运行了maven的clean命令,并且重新compile命令,那么就会发现在target文件夹下,application.properties文件已经无了。

所以除了上面这个resource标签所指定的内容以外,还要加上另一部分(上保险):

<resource>
   <directory>src/main/resources</directory>
   <includes>
      <include>**/*.*</include>
   </includes>
</resource>

上面的代码指定application.properties也作为配置文件的一部分,这个时候我们如果learn、conpile的话,就会发现它又回来了,并且原来的StudentMapper.xml也没有消失。

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_mybatis_10

@Service

之前我们在service层中添加过这个注解,这个注解告诉springboot其声名的类属于业务层,该类会放在容器中,用于在控制层注入

该注解用于实现类

主要的几种用法:

  • 最常用的用法
@Service
public class TestServiceImp implements TestService {
    //
}
@RestController
public class TestController {
 
    @AutoWired
    private TestService testService;
	
}
  • 当一个interface有多个实现类的时候的用法
@Service("testService")
public class TestServiceImp implements TestService {
	//
}
@RestController
public class TestController {
 
    @AutoWired
    // 这个变量名testService和@Service()的命名(即参数)一致
    private TestService testService; 
	
}

当然这种情况还有其他方式

@Service("testService")
public class TestServiceImp implements TestService {
    //
}
@RestController
public class TestController {
 
    @Resource(name = "testService") // 这个值testService和@Service("")的命名一致
    private TestService testService;
	
}
@Mapper

作用是将标注的DAO接口交给Spring进行管理,并且为该接口生成一个实现类放在容器中,给业务层的实现类使用

该注解用于数据持久层的接口

方法参数有多个的时候,需要使用@Param,单参数方法不需要

(6)测试
成功拿到数据库的数据

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_java_11

(7)总结过程描述

整个过程,其实就是控制层接收前端传来的参数之后,调用studentService的queryStudentById方法,该方法返回一个Student实例,Springboot会去容器中找到被@Service注解标注的studentService接口的实现类StudentServiceImpl,然后调用里面的queryStudentById放方法,StudentMapper接口由于被@Mapper标注,所以会在Spring容器中实例化一个实现类,所以queryStudentById方法就可调用持久层中的studentMapper实例的selectByPrimaryKey方法,该方法在StudentMapper.xml配置文件中返回BaseResultMap值,Mybatis会根据查询语句,返回一个符合条件的对象。

3.1.3 DAO 的第二种开发方式

上面的连接方式是只有一个DAO的情况下,当我们有多个DAO的时候,我们可以用另一种写法,而不是在每一个DAO里面写@Mapper

(1)添加@MapperScan

第二种方式我们主要使用原来的方法:对包扫描映射文件,此时需要用到注解@MapperScan,其参数通常指定到数据持久层包即可

在运行主类 Application 上加@MapperScan(basePackages = “com.example.springbootworkspace.mapper”)

@SpringBootApplication
@MapperScan(basePackages = "com.example.springbootworkspace.mapper")
public class SpringbootWorkspaceApplication {

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

}

注意,此时DAO接口(mapper包里的接口)上就不需要加@Mapper注解了。

(2)将接口和映射文件分开

这个时候因为不使用@Mapper了,Springboot不能自动编译接口映射的xml文件了,这个时候也不像上个案例那样子通过@Mapper在容器中生成持久层实例放入业务层中了,所以我们还需要做一点小小的改动

找到resources文件夹,我们在它下面创建一个mapper文件夹,接下来我们需要把mapper包下的StudentMapper.xml文件放到mapper文件夹下:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_spring boot_12

(3)指定Mybatis映射文件路径

这个时候我们发现:接口和映射文件分开了,这种情况Springboot要求我们要在application.properties中指定映射文件的位置

mybatis.mapper-locations=classpath:mapper/*.xml
(4)测试

运行项目进行测试,可以看到冇问题:

springboot 使用mybatis 兼容表名大小写 springboot mybatis databaseid_mysql_13