简介

什么是 MyBatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

使用方法

快速入门

首先在Maven配置文件中引入MyBatis依赖

这个是MyBatis的仓库链接 https://mvnrepository.com/artifact/org.mybatis/mybatis 在项目下的pom.xml文件中的dependencies插入这个依赖,然后点击同步即可。JDBC的话请根据自己的数据库类型和版本来选择。

        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>

在Resources文件夹中创建MyBatis配置文件/例如MyBatisConf.xml

img

<?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>
    <!--typeAliases可以让Usermapper.xml文件中定义的result直接写对应的类名就行了,typeAliases必须放在环境上面-->
    <typeAliases>
        <package name="com.hash070.pojo"/>
    </typeAliases>
    <!--environments 数据库环境信息,可以配置多个,方便开发管理-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://[ip]:[端口]/[数据库名]?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true"/>
                <!--注意这里需要转义,否则会报错,&amp为转义标识-->
                <property name="username" value="用户名"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--加载sql的映射文件-->
        <mapper resource="com.hash070.mapper/UserMapper.xml"/>
    </mappers>
</configuration>

创建Mapper文件/例如UserMapper.java

Mapper共有两个,一个是一个java接口文件,用于定义接口

另一个是一个xml文件,用于实现接口

下面这个是接口mapper

img

接口内容:

package com.hash070.mapper;

import com.hash070.pojo.User;

import java.util.List;

public interface UserMapper {
    List<User> selectAll();
}

然后是和接口同名但后缀不同的mapper,用于实现接口,为方便管理,我将这个文件放在了resources目录下,但最后编译的时候该文件和上面的接口文件是会放在一起的,只要文件夹是按照这个命名方式就行。

img

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.hash070.mapper.UserMapper">
<!--    id为sql语句的唯一标识,要与接口名称一致-->
    <select id="selectAll" resultType="User">
        select * from userTable;
    </select>
</mapper>

创建POJO类

****POJO(****Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。

POJO在MyBatis中用于规定返回的类型,MyBatis一般不会返回结果集(ResultSet),而是返回一个数或者一些封装着查询结果的JavaBean,方便程序处理,让代码维护起来更加方便。

img

例如我在查询用户表时,需要返回一堆用户数据,那么我就定义一个用户实体类,设置好getter和setter方法即可。

package com.hash070.pojo;
public class User {
    int id;
    String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

在代码中使用示例

        //1.加载Mybatis 核心配置文件
        String resource = "MyBatisConf.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取sqlSession 对象,使用它来执行方法
        SqlSession sqlSession = sqlSessionFactory.openSession(true);//建议开启自动提交事务
        //3.利用sqlSession,执行编码好的sql语句
        List<User> users;
        users = sqlSession.selectList("user.selectAll");//第一种方法:命名空间+方法
        StuMapper mapper = sqlSession.getMapper(UserMapper.class);//第二种方法:可以通过获取Mapper对象的方式来执行方法
        users = mapper.selectAll();//用mapper对象执行方法
        //selectList表示返回一串方法
        for (User u :
                users) {
            System.out.println("用户名:"+u.getName()+"\tID:"+u.getId());
        }
        System.out.println(users);
        //4.关闭sqlSession
        sqlSession.close();

好的,这就是MyBatis的基本使用流程了

  1. 创建配置文件
  2. 创建mapper接口并实现接口
  3. 创建pojo类
  4. 在程序中调用MyBatis

进阶内容

在上面的那个例子中只展示了MyBatis的基本使用流程,并不包含如何进行增删改查的操作,下面将着重介绍这些内容

第一部分:数据库查询

普通的不带参数的数据库查询方法

关于ResultMap的使用

值得注意的是,MyBatis没有那么智能,数据库字段和实体类中的属性名称需要保持一致才能实现将查询的信息封装到POJO实体类中,如果它们不一致,则不能自动匹配。

解决方案1:在查询的SQL语句中设置别名

又因为起别名时非常麻烦,不方便

解决方案2:使用SQL片段来实现重复利用含有别名的sql

推荐解决方案:使用ResultMap实现数据库字段到实体类属性名的映射

使用方法:

在Mapper的xml文件中写一段像这样的resultMap

<!--type指的是映射实体类-->
    <resultMap id="stuResultMap" type="Student">
<!--        下面的id用于完成主键映射,result完成一般映射-->
<!--        从列名映射到了代码中实体类定义的变量名-->
        <id column="sno" property="no"/>
        <result column="sname" property="name"/>
        <result column="sgender" property="gen"/>
    </resultMap>

然后在需要返回的方法中标注返回类型为上面的resultMap的名称就行了

例如,allStu方法需要查询数据中所有的学生信息:

    <select id="allStu" resultMap="stuResultMap">
        select *
        from student;
    </select>

带参数的数据查询方法

如果需要在数据库中查询特定的学生信息,就需要用到参数了。

例如findStuByNo是一个通过学号查找学生的方法,需要一个int类型的id作为参数

<select id="findStuByNo" parameterType="int" resultMap="stuResultMap">
    select *
    from student
    where sno = #{sno};
</select>

在这段代码中,最重要的是占位符,大括号里面的“sno”,指的是这里填写传递进来的名为sno的参数。

这里的大括号里面的东西指的是接口里面的字符串。
        参数占位符有
        1. #{}:会将其替换为?,等价于jdbc中的预编译SQL的"?"
        2. ${}:利用字符串拼接的方法获得的,会存在sql注入问题
        3. 使用时机,传递参数一般使用#
        而当表名或者列名不固定的话就可以使用${}了

注:上述示例代码中parameterType指的是参数类型,这个可以不写,因为MyBatis可以自动识别,但返回类型和参数占位符必一定要写。

调用方法:

在mapper接口中写好这个接口

    Student findStuByNo(int sno);

然后在程序中利用mapper对象来执行方法就完事了

    Student stu = mapper.findStuByNo(111);

多条件查询

关于在多条件查询中常用的几种传参方法

1**.散装参数法**

@Param(“参数占位符的名称”) [变量类型] [变量名]

注意,即使变量名和参数名一致,MyBatis也不会自动将它们对上号,必须把@Param写上去,否则会报错。

Student findStuByMul(@Param("name") String name,@Param("gen") String gen);

2.对象传参法

利用对象中来传递参数,要注意对象的属性名称要和占位符名称(就是大括号里面的那个)一致

Student multi(Student stu);

3.键值对法

也可以把一个键值对以[属性名][值]的方式把参数传递进去

Student multi(Map map);

使用方法:新建一个键值对对象,往里面填充信息,注意键名和占位符名保持一致。

Map map = new HashMap();
map.put("name", "小李");
map.put("gen", null);
System.out.println(mapper.multi(map));

动态多条件查询

一般情况下,当使用多条件查询时,如果条件不全将会导致查询出错,如果将所有的情况都列出来分别对应一个SQL,将会让工作量剧增且让代码难以维护。

这时就需要用到动态SQL技术了,幸运的是MyBatis对于动态SQL的支持很好。

SQL语句随着用户的输入或外部条件的变化而变化,称为动态SQL。

使用方法:在MapperXml文件中的SQL代码块中,可以使用if标签即可通过逻辑判断动态调整

例如下面的这几行代码,只要name或gen这两个参数中有一个缺失,就会导致查询出错。

解决方案就是使用if判断参数是否为空,从而实现动态组合SQL。

问题代码
    <select id="multi" resultMap="stuResultMap">
        select * from student
        where sname=#{name}
        and   sgender=#{gen};
    </select>
解决方案一:用if判断一下,前面加一个恒等式以满足语法要求
    <select id="multi" resultMap="stuResultMap">
        select * from student
        where 1=1
            <if test="name!=null">
                  and sname=#{name}
              </if>
            <if test="gen!=null">
                  and sgender=#{gen}
            </if>
            ;
    </select>
解决方案二:(推荐)用<where>标签,可以省略掉恒等式,让代码更加优美
    <select id="multi" resultMap="stuResultMap">
        select * from student
        <where>
                  <if test="name!=null">
                      and sname=#{name}
                  </if>
                <if test="gen!=null">
                      and sgender=#{gen}
                </if>
        </where>
    </select>

单条件动态查询

说完了多条件动态查询,我们再来说说单条件动态查询。

有没有可能让一个单条件语句实现多种情况的查询呢?

例如我想通过只写一段mapper代码,让这一段mapper代码即能通过学号查询学生,又能通过姓名查询学生,还能通过学院来查询学生,MyBatis可以做到吗?

答案是可以做到,在MyBatis中,存在类似于switch case这样的语句来实现上述需求。

例如下面的这一段代码

<!--    单条件的动态查询choose when otherwise相当于Switch case default语句-->
    <select id="switchCase" resultMap="stuResultMap">
        select * from student
        where
            <choose>
                <when test="name!=null and name!=''">
                    sname=#{name}
                </when>
                <when test="gen!=null and gen!=''">
                    sgender=#{gen}
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
    </select>
还有一种方法,和上面的类似,但不完全一样
上面的当所有内容为空时,查询不出任何内容
下面的当所有内容为空时,查询出所有内容
因为当所有内容为空时,MyBatis会自动将where去掉以满足语法要求
    <select id="switchCase" resultMap="stuResultMap">
        select * from student
        <where>
            <choose>
                <when test="name!=null and name!=''">
                    sname=#{name}
                </when>
                <when test="gen!=null and gen!=''">
                    sgender=#{gen}
                </when>
            </choose>
        </where>

其中相当于switch,相当于case,相当于default

Q.E.D.