# MyBatis入门介绍

## 1. MyBatis简介

MyBatis是支持普通SQL查询、存储过程和高级映射的持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射，将接口和Java的POJOs映射成数据库中的记录。

一般情况下MyBatis是被Spring整合使用的，但是他也可以独立使用。

## 2. 独立使用MyBatis步骤：

1. 建立PO类。用于对数据库中数据的映射，使程序员更关注对Java类的使用而不是数据库的操作。
2. 建立Mapper。数据库操作的映射文件，也就是我们常常说的DAO，用于映射数据库的操作，可以通过配置文件指定方法对应的SQL语句或者直接使用Java提供的注解方式进行SQL的指定。
3. 建立配置文件。配置文件主要用于配置程序中可变性高的设置，MyhBatis中的配置文件主要封装在configuration中。
4. 建立映射文件。对应于MyBatis全局配置中的mappers的配置属性。主要用于建立对应数据库操作接口的SQL映射。MyBatis会将这里设定的SQL与对应的Java接口相关联，以保证在MyBatis中调用接口的时候会到数据库中执行相应的SQL来简化开发。

**建立测试类。进行测试**

**代码实例：**

### 建表

```sql
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

### 1）建立PO类。

```java
package com.wangjun.mybatis.test.mybatis;

public class User {
private Integer id;
private String name;
private Integer age;
public User(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
//必须要有这个无参构造器，不然根据UserMapper.xml中的配置，在查询数据库的时候，将不能呢过反射构造出User实例
public User() {
}

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

### 2）建立Mapper。

```java
package com.wangjun.mybatis.test.mybatis;

public interface UserMapper {
    public void insertUser(User user);
    public User getUser(Integer id);
}
```

### 3)  建立配置文件

路径：src/main/resources/mybatis/mybaits-config.xml

```markup
<?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>
    <settings>
        <setting name="cacheEnabled" value="false"></setting>
        <setting name="useGeneratedKeys" value="true"></setting>
        <setting name="defaultExecutorType" value="REUSE"></setting>
    </settings>
    <typeAliases>
        <typeAlias alias="User" type="com.wangjun.mybatis.test.mybatis.User"/>
    </typeAliases>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <!-- 新版本的jdbc建议使用com.mysql.cj.jdbc.Driver -->
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <!-- 不加 ?serverTimezone=GMT 可能会有数据库时区和系统时区不一致导致的问题 -->
        <property name="url" value="jdbc:mysql://localhost/test?serverTimezone=GMT"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="mybatis/UserMapper.xml"/>
  </mappers>
</configuration>
```

### 4) 建立映射文件。

路径：src/main/resources/mybatis/UserMapper.xml

```markup
<?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.wangjun.mybatis.test.mybatis.UserMapper">
    <insert id="insertUser" parameterType="User">
        insert into user(name,age) values(#{name},#{age})
    </insert>
    <select id="getUser" resultType="User" parameterType="java.lang.Integer">
      select * from user where id = #{id}
    </select>
</mapper>
```

### 5) 测试类

```java
package com.wangjun.mybatis.test.mybatis;

import java.io.IOException;
import java.io.RString resource = "mybatis/mybaits-config.xml";eader;

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

public class MyBatisUtil 
{
    private final static SqlSessionFactory sqlSessionFactory;
    static {
        String resource = "mybatis/mybaits-config.xml";
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    }
    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}
```

```java
package com.wangjun.mybatis.test.mybatis;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

public class TestMapper {
    static SqlSessionFactory sqlSessionFactory = null;
    static 
        sqlSessionFactory = MyBatisUtil.getSqlSessionFactory();
    }

    public void testAdd() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = new User("wangjun", new Integer(25));
            userMapper.insertUser(user);
            sqlSession.commit();
        }finally {
            sqlSession.close();
        }
    }
    public void getUser() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = userMapper.getUser(1);
            System.out.println("name:" + user.getName() + "|age:" + user.getAge());
        }finally {
            sqlSession.close();
        }
    }

    public static void main(String[] args) {
        TestMapper tm = new TestMapper();
        tm.testAdd();
        tm.getUser();
    }
}
```

运行结果：

```bash
name:wangjun|age:25
```

### #) 补充，POM文件配置

mybatis运行需要依赖jdbc和myBaits

```markup
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wangjun.mybatis</groupId>
    <artifactId>test.mybatis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test.mybatis</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
    </dependencies>
</project>
```

## 3. Spring整合MyBatis步骤：

上述步骤的1,2,4步不变。需要配置Spring文件：

### 1) Spring配置文件

路径：src/main/resources/mybatis/springMyBatis.xml

将MyBatis配置文件的environments配置移动到了Spring的配置文件中。针对MyBstis，注册org.mybatis.Spring.SqlsessionFactoryBean类型的bean，以及用于映射接口的org.mybatis.Spring.mapper.MapperFactoryBean。

```markup
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 需要maven依赖commons-dbcp包 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost/test?serverTimezone=GMT"></property>
        <property name="username" value="root"></property>
        <property name="password" value="password"></property>
        <property name="maxIdle" value="30"></property>
        <property name="defaultAutoCommit" value="true"></property>
    </bean>

    <!-- 需要maven依赖mybatis-spring和spring-jdbc包 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="mybatis/configuration.xml"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.wangjun.mybatis.test.mybatis.UserMapper"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>
</beans>
```

### 2) 简化MyBaits的配置文件

路径：src/main/resources/mybatis/configuration.xml

MyBatis的配置文件简化。

```markup
<?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>
        <typeAlias alias="User" type="com.wangjun.mybatis.test.mybatis.User"/>
    </typeAliases>
  <mappers>
    <mapper resource="mybatis/UserMapper.xml"/>
  </mappers>
</configuration>
```

### 3) 测试类

Spring整合MyBatis很简单，我们可以看到除了MyBaits配置文件的更改并没有太大变化。其实Spring整合MyBatis的优势主要在于使用上，我们来看看Spring中使用MyBatis的用法：

```java
package com.wangjun.mybatis.test.mybatis;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringMyBatisTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("mybatis/springMyBatis.xml");
        UserMapper um = context.getBean("userMapper", UserMapper.class);
        //查询数据
        User user = um.getUser(1);
        System.out.println(user.getName());
        System.out.println(user.getAge());

        //插入数据
        User addUser = new User("lujiashaoye", 24);
        um.insertUser(addUser);
    }

}
```

我们可以看到，在Spring中使用MyBatis非常方便，用户甚至无法察觉自己正在使用MyBatis，而这一切相对于独立使用MyBatis时必须要做的冗余操作来说无非是打打简化了我们的工作量。

## 4. 与Hibernate的区别

两者的增删查改对于业务逻辑层来说大同小异，区别主要体现在：

1. Hibernate不需要手写SQL，直接操作pojo类，Hibernate会根据映射关系生成对应的SQL，对于早期的管理系统注重实现业务逻辑，因此hibernate成为了主流。MyBatis需要手写SQL，这样能更加精准的定义SQL，从而优化性能，因此在互联网时代后，更适合互联网高并发，大数据，高性能，高影响的要求，代替hibernate成为主流的持久性框架。
2. 由于MyBatis需要写SQL和接口，工作量可能大一些。

所以在管理系统，ERP，CRM等对性能要求不高的系统推荐使用Hibernate，对于性能要求高、响应快、灵活的系统则推荐使用MyBatis。

## 5. MyBaits核心组件

* SqlSessionFactoryBuilder：根据配置文件（就是前面的mybatis-config.xml）或者代码生成SQLSessionFactory，采用builder模式。
* SqlSessionFactory：类似数据库连接池，使用工厂模式生产SQLSession。
* SqlSession：类似数据库连接对象，可以发送SQL执行返回结果。
* SQL Mapper：SQL映射器，由java接口和xml（或者注解）构成，需要给出映射规则，它负责发送SQL去执行，并返回结果。

一般情况下mybaits执行sql的整个流程如下：

SqlSessionFactoryBuilder根据配置文件读取configuration配置，使用builder模式创建SqlSessionFactory，SqlSessionFactory一般采取单例模式，SqlSessionFactory通过openSession()方法创建SqlSession，SqlSession可以直接发送SQL执行，也可以获取mapper，通过mapper接口发送SQL执行。

**XML和注解的区别**

一般简单的sql可以使用注解，由于都在java包里面，维护和查看比较方便，但是如果有些复杂的sql注解无法实现这个时候就要使用xml的配置方式了。

## 6. MyBatis的解析和运行原理

MyBatis的运行分为两个过程：

* 读取配置文件缓存到Configuration对象，用以构建SQLSessionFactory的过程；
* SqlSession的执行过程。

### 6.1 构建SQLSessionFactory的过程

第一步，通过XMLConfigBuilder解析配置的XML文件，读出所配置的参数，并将读取的内容存入Configuration对象中，而Configuration采用的是单例模式，几乎所有的MyBatis配置内容都会存放在这个单例对象中，以便后续将这些内容读出；

第二步，使用Configuration对象创建SQLSessionFactory，MyBatis中的SQLSessionFactory是一个接口，为此MyBatis提供了一个默认的实现类DefaultSQLSessionFactory。在大部分情况下，都没有必要自己去创建新的SQLSessionFactory实现类。

### 6.2 SqlSession的执行过程

> 《Spring源码深度解析》笔记
>
> 《JavaEE互联网轻量级框架整合开发（SSM和Redis实现）》笔记


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jun-wang.gitbook.io/learnjava/ji-shu-xue-xi/spring/mybatis-ru-men-jie-shao.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
