Mybatis入门实例解析

写在前面:本文全程根据Mybatis官网进行入门讲解。毫无疑问,官方文档是学习这门技术最权威的资料,与此同时我们也知道官方文档对待入门小白基本上不太友好,没有入门demo、开篇就是小白们不懂的内容、有些甚至没有对应的中文文档;这些都一定程度上打击了我们的学习兴趣,也降低了我们学习效率。幸运的是,Mybatis的官网有中文文档供我们学习使用,这为我们的学习清除了语言不通这一大障碍。所以我建议打开Mybatis入门,边看官网进行接下来的学习。【注以下官方文档简称文档】

学到这里相信大家都已经知道什么是Mybatis是吧,官方对Mybatis的解释是:MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。当然,现实点说我们之所以学习Mybatis还是因为大家都在用这个框架。下面我将具体讲解Mybatis的入门。


  1. 使用Maven来构建项目你的Mybatis项目。
    1. pom.xml 文件中添加Mybatis依赖
    2. 其他依赖
  2. 获取SqlSessionFactory对象
    1. mybatis-config.xml配置
    2. 通过SqlSessionFactoryBuilder来构建基于XML的SqlSessionFactory
  3. Mapper映射SQL 语句
    1. 编写数据库实体类
    2. 编写Mapper接口
    3. Mapper接口与Mapper映射器的映射
  4. 获取SqlSession对象进行具体的操作
    1. SqlSession调用Mapper接口方法实现数据操作

使用Maven来构建项目你的Mybatis项目。

1. pom.xml 文件中添加Mybatis依赖

文档开篇既表明了Mybatis项目需要依赖mybatis-x.x.x.jar
Mybatis入门实例解析
因此我们在创建的项目中导入mybatis依赖。

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
</dependency>

2. 其他依赖

Mybatis是简化对数据库的操作,毫无疑问我们还需要mysql依赖,这里我顺便还把junit导入进来,方便后面的测试使用。具体的依赖为如下

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

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

    </dependencies>

做好这些前提条件后,我们就愉快地可以进行下一步了。

获取SqlSessionFactory对象

1. mybatis-config.xml配置

看了文档,我们知道,获取SqlSessionFactory有两种办法,一种是从 XML 中构建 SqlSessionFactory,另一种是不使用 XML 构建 SqlSessionFactory。也就是我们即将开始的第二小步。当然官方当然是更加推荐我们使用配置XML的方式来构建SqlSessionFactory。框架的本质就是为了简化开发,将一些配置信息写入配置文件来简化开发流程。
既然如此,我们首先就要创建这个xml配置文件喽。
Mybatis入门实例解析
首先我们在项目的resources资源目录小创建一个mybatis-config.xml文件,内容如下:

<?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>
    <!--环境,可以配置多个环境,这里设置了默认的环境为development-->
    <environments default="development">
        <!--第一个环境时id为development的环境-->
        <environment id="development">
            <!--事务管理是JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据池配置-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--****分别对应你数据库信息-->
                <property name="url" value="jdbc:mysql://****?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="****"/>
                <property name="password" value="****"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

有了这个配置文件,SqlSessionFactory对象就知道了要对哪个数据库进行操作,通过用户名和密码获得了对数据库进行操作的权限。
细心的你会发现,我这里的配置信息相较于官网,少了一对标签。标签中mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。现在不需要了解,接下来我们会使用到。

2. 通过SqlSessionFactoryBuilder来构建基于XML的SqlSessionFactory

先让将文档滑倒底部,我们可以看到以下信息:
Mybatis入门实例解析
简单地说,SqlSessionFactoryBuilder唯一作用就是为了创建SqlSessionFactory,并且只需要使用一次,当创建了SqlSessionFactory后就不再需要了,所以文档中也说明了SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。而SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,因此SqlSessionFactory 的最佳作用域是应用作用域。也就是SqlSessionFactoryBuilder只用一次,而SqlSessionFactory需要一直使用。根据这一特性,我们完全能把构造SqlSessionFactory的操作具体成为一个工具类,那么当我们需要使用SqlSessionFactory的时候只需要通过这个工具类获取。因此,我们新建一个MybatisUtils类,存放在utils包下面.

package com.th.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @description: 工具类,通过 SqlSessionFactory 获取 SqlSession,避免每次使用都new一个SqlSession
 * @since 1.8
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //第一步:获取SqlSessionFactory对象
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在
    数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。*/

    public static SqlSession getSqlSession(){
        //通过静态代码块中的sqlSessionFactory对象调用openSession()方法得到一个SqlSession 对象
        //将这个SqlSession 对象返回出去,作为工具提供给需要实现数据库操作的对象使用。
        return sqlSessionFactory.openSession();
    }
}

在上述代码中,首先通过MyBatis包含一个名叫 Resources 的工具类下的getResourceAsStream()方法来获取配置文件信息流,然后再根据SqlSessionFactoryBuilder()的build()方法传入这个流信息,从何返回一个sqlSessionFactory 对象。最后在静态方法getSqlSession()中通过sqlSessionFactory 对象调用openSession()方法返回一个SqlSession 对象。在接下来所有数据库操作,只需要通过SqlSession sqlSession = MybatisUtils.getSqlSession()就可以获得一个sqlSession 。
通过上面讲解,我们可以清晰的看出,SqlSessionFactoryBuilder --创建--> SqlSessionFactory --创建-> SqlSession 。至此,我们已将完成了第二大步骤了。

Mapper映射SQL 语句

1. 编写数据库实体类

一个实体类对应的就是一个数据表,这里我有一个User表,那么为对应有一个User类。特别需要注意的是,实体类定义的变量需要与数据表中的字段一一对应。
Mybatis入门实例解析

package com.th.pojo;

/**
 * @description: user表的实体类
 * @since 1.8
 */
public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    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;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

2. 编写Mapper接口

所谓Mapper接口,这是在mybatis中特有的说法,在jdbc中相当于Dao层,在这个结口上,定义所有的数据库操作方法,比如getUserList()。在传统的数据库操作中,通过Dao层的方法,定义所有的数据操作方法,然后通过实现类对这个接口的实现具体行为。在Mybatis中,Dao层还是哪个Dao层,只是不叫作Dao层,一般也不命名为UserDao而是改用Mapper接口的说法。其实他们是一样的。

package com.th.dao;

import com.th.pojo.User;
import java.util.List;
import java.util.Map;

/**
 * @description: user表的Dao层接口
 * @since 1.8
 */

/**相当于JDBC中的UserDao*/
public interface UserMapper {
    /**
     * @description: 查询所有的用户
     * @Param: []
     * @Return: java.util.List<com.th.pojo.User>
     */
    List<User> getUserList();

    /**
     * @description: 通过id查询一个用户
     * @Param: [id]
     * @Return: com.th.pojo.User
     */
    User getUserById(int id);

    /**
     * @description: 插入一个用户
     * @Param: [user]
     * @Return: int
     */
    int insertUser(User user);

    /**
     * @description: 插入用户
     * @Param: [map]
     * @Return: int
     */
    int insertUser2(Map<String,Object> map);

    /**
     * @description: 更改用户
     * @Param: [user]
     * @Return: int
     */
    int updateUser(User user);

    /**
     * @description: 根据id删除用户
     * @Param: [id]
     * @Return: int
     */
    int deleteUser(int id);
}

3. Mapper接口与Mapper映射器的映射

按照jdbc所学,接下来就是对Dao层接口中所有方法进行具体实现类。Mybatis的引入就是为了免除几乎所有的 JDBC 代码以及设置参数和获取结果集的工作,如果我们还是那样做,那就失去了使用框架的意义,因为这样步骤依然繁琐。
在Mybatis中,已经没有了UserImpl的概念,取而代之的是用一个基于 XML 的映射语言来实现。对,你没有看错,又是XML文件,毕竟框架就是大量的使用配置文件来减少java语言的编写。对于初学者,可以理解为这样一个XML配置文件就是原来UserImpl的替代品,而这个XML文件就可以称为Mapper映射器。在这个XML配置文件中将我们需要的sql语句写在这里。如官网1所示:
Mybatis入门实例解析
看到这里,你会很好奇<mapper namespace=" "></mapper>namespace是上面,还有,这个配置文件跟Dao层(Mapper接口)的接口有什么关系?其实,这两者的联系就是通过namespace的值形成映射关系的。通过这种映射关系,使得Mapper接口和Mapper映射器形成一一对应的关系。
当我们在<mapper>标签中按下<键,IDEA就很智能的提示我们有那些操作,而这些操作,不就是对应我们对数据库的增删改查嘛。
Mybatis入门实例解析
而没一个数据操作,在对应的标签内都有对应的参数,如id=""就是对应Mapper接口中的方法,parameterType就是表示参数类型,这些参数的使用我们可以通过查询相关文档来了解他们的用法。下面就是一些简单的配置案例了:

<mapper namespace="com.th.dao.UserMapper">
    <!--select查询语句-->
    <!--id为Dao/Mapper接口的一个方法,resultType为返回的一个类型-->
    <select id="getUserList" resultType="com.th.pojo.User">
        select * from mybatis.user
    </select>

    <select id="getUserById" parameterType="int" resultType="com.th.pojo.User">
        select * from mybatis.user where id=#{id}
    </select>

    <insert id="insertUser" parameterType="com.th.pojo.User">
        insert into mybatis.user(id,name,pwd) values (#{id},#{name},#{pwd});
    </insert>

    <!--传递map的key-->
    <insert id="insertUser2" parameterType="map">
        insert into mybatis.user (id,name,pwd) values (#{userid},#{userName},#{passWord});
    </insert>
    
    <update id="updateUser" parameterType="com.th.pojo.User">
        update mybatis.user set name =#{name},pwd=#{pwd} where id=#{id};
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id};
    </delete>

</mapper>

这里我还要对namespace属性进行补充,namespace有两种写法。

全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用。
短名称(比如 “selectAllThings”)如果全局唯一也可以作为一个单独的引用。 如果不唯一,有两个或两个以上的相同名称(比如 “com.foo.selectAllThings” 和 “com.bar.selectAllThings”),那么使用时就会产生“短名称不唯一”的错误,这种情况下就必须使用全限定名。

获取SqlSession对象进行具体的操作

1. SqlSession调用Mapper接口方法实现数据操作

做到这里,所有的前提工作已经基本准备就绪了,现在我们只需要去使用了,根据文档的案例:
Mybatis入门实例解析
那我们在学习中,就尽可能的使用第二种方法。通过SqlSession对象的getMapper()方法来得到Mapper接口,再通过这个接口的具体某一个方法对数据库进行操作而得到响应结果。此时,你可能会认为这一套全程mybatis的使用就结束了,因为我们已经得到了我们想要的结果。其实不然,跟jabc一样,对数据库进行操作后都与需要关闭响应的流。根据文档显示,我们需要在返回一个响应后,就关闭它SqlSession。最好的解决方案是使用try-catch-finally语句,在finally中将其关闭。
Mybatis入门实例解析

package com.th.dao;

import com.th.pojo.User;
import com.th.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ThreePure
 * @date 20/12/16 20:26
 * @description:UserDao测试
 * 1.配置文件没有注册
 * 2.绑定接口错误。
 * 3.方法名不对
 * 4.返回类型不对
 * 5.Maven导出资源问题
 * @since 1.8
 */
public class UserMapperTest {
    @Test
    public void testGetUserList() {
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        try {
            //方式一:getMapper(推荐使用)
            //不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> userList = userMapper.getUserList();

            //方式二:
//        List<User> userList = sqlSession.selectList("com.th.dao.UserDao.getUserList");

            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭SqlSession
            sqlSession.close();
        }
    }
}

最后,你可能未必能够得到正确的结果,你可能会遇到一个java.lang.ExceptionInInitializerError的错误。关于这个错误,我在Mybatis配置错误中有具体的解答。

上一篇:Mybatis中重要组件的生命周期


下一篇:sqlSessionFactoryBuilder SqlSessionFactory 和 SqlSession