Mybatis(一)

Mybatis(一)

Mybatis

本文基于 Mybatis官方文档

一、Mybatis 简介

1.1 什么是 Mybatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

1.2 什么是持久层

在了解持久层之前,我们首先得明白什么是持久化。持久化(Persisent)指的是将内存中的数据保存到磁盘等存储设备中,而持久化对象是指已经存储到数据库或磁盘中的业务对象。

持久层,又叫数据访问层(Dao层),是和数据库直接打交道的层。就是把增删改查都封装进一个层中管理。

1.3 安装 Mybatis

1.3.1 依赖安装

如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml:

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

这三个依赖分别是 Mybatis 核心依赖、MySql 数据库依赖以及 junit 单元测试依赖

1.3.2 XML 文件 和 工具类

在 resources 文件夹中创建一个 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>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。我们可以从中获得 SqlSession 的实例。

我们可以使用工具类来避免重复代码,通过调用下面类的一个 getSqlSession() 方法,我们可有得到一个 SqlSession 实例。

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;

/**
 * 使用 XML 构建 sqlSessionFactory
 * 从 sqlSessionFactory 中拿到 sqlSession
 * @author Reimu
 */
public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            // 获取 sqlSessionFactory 对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得 sqlSession 对象
     * @return 返回一个 sqlSession 对象
     */
    public static SqlSession getSqlSession() {
        // 同时开启事务
        return sqlSessionFactory.openSession(true);
    }
}

到这里,Mybatis 的安装就结束了。

1.3.3 作用域

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。


二、第一个Mybatis 项目

接下来我们要开始着手编写第一个 Mybatis 项目了。

2.1 建立数据库

我们登录 Mysql 数据库,并执行下面一段 SQL:

create database kimari;

use kimari;

create table user(
    id   int(20) not null primary key,
    name varchar(30) default null,
    pwd  varchar(30) default "123456"
) engine = innodb
  default charset = utf8;

insert into user (id, name, pwd)
values (1, "曹超", "123456"),
       (2, "陈浩南", "123456"),
       (3, "程中星", "123456");

在登录 Mysql 的时候可以在 Mybatis 核心配置文件中的 property 标签中填写数据库相关信息

2.2 创建实体层和持久层

实体层: 每个属性对应数据库中的字段

/**
 * 对应数据库的 User 表
 *
 * @author Reimu
 */
public class User {
    private int id;
    private String name;
    private String pwd;

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

    public User() {
    }

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

持久层:相当于原先 jdbc 中的 dao,在这里称为 mapper。在这里我们写上一个查询所有 User 的方法。

import com.kimari.pojo.User;

import java.util.List;

/**
 * User 接口
 *
 * @author Reimu
 */
public interface UserMapper {
    /**
     * 获取所有的 User
     * @return 返回 User 集合
     */
    List<User> getUserList();
}

2.3 编写 XML 映射器

Mybatis 的强大之处莫过于 XML 映射器,现在我们简单的编写一个映射器。在 UserMapper 类下创建一个 UserMapper.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">
    <!--命名空间是指该 xml 映射了哪个dao -->
<mapper namespace="com.kimari.dao.UserMapper">
	<select id="getUserList" resultType="com.kimari.pojo.User">
        select *
        from kimari.user;
    </select>
</mapper>

稍后我们会介绍映射器中的具体标签和参数。

2.4 注册 Mapper

最后一步也是最关键的一步,当我们每次写完一个 Mapper 映射器之后。需要将它注册到 Mybatis 核心配置文件(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>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/kimari?useUnicode=true&amp;
                    characterEncoding=utf-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/kimari/dao/UserMapper.xml"/>
    </mappers>
</configuration>

2.5 测试

测试代码和结果如下:

import com.kimari.dao.UserMapper;
import com.kimari.pojo.User;
import com.kimari.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {
    @Test
    public void test() {
        //第一步,获得 sqlSession 对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步,执行 sql
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();

        for (User user : userList) {
            System.out.println(user);
        }
        //第三步,关闭 sqlSession
        sqlSession.close();
    }
}

    /** 输出结果:
     * User{id=1, name="曹超", pwd="123456"}
     * User{id=2, name="陈浩南", pwd="123456"}
     * User{id=3, name="程中星", pwd="123456"}
     */

到此我们完成了我们的第一个 Mybatis 项目。