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

Mybatis的官方网站为:https://mybatis.org,项目的仓库地址为:https://github.com/mybatis/mybatis-3,可通过访问官网或仓库获取最新版本的 Mybatis。

下面将介绍 Mybatis 的安装和配置。

一、安装

安装 Mybatis 有以下两种方法,推荐使用 Maven 导入依赖

1、通过下载JAR

可直接从 Mybatis 的 发行版 中下载所需要的版本,然后将下载的JAR置于项目类路径(classpath)中即可。

2、通过Maven导入依赖

打开 Maven 项目的pom.xml,添加以下内容:

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>

注:version标签中的内容为 Mybatis 的版本,请根据实际项目需要选择相应的版本或访问 Maven Repository

查询 Mybatis 的所有发行版本。

二、入门

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

官方文档中对SqlSessionFactoryBuilderSqlSessionFactorySqlSession的解释如下:

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

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

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

下面将以一个完整的案例来说明如何在项目中配置并使用 Mybatis 框架:

案例

假设在数据库中存在一个person表,现在需要查出person表中的所有信息并打印到控制台,person表包含nameage两个字段,该表的建表SQL语句如下:

1
2
3
4
5
CREATE TABLE `person` (
`name` varchar(255) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`name`)
);

如果要用Mybatis框架该如何去实现呢?下面将给出完整的实现过程。

1、新建一个Maven工程

以 IDEA 为例创建一个 Maven 工程。

创建项目-1

创建项目-2

创建项目-3

在点击完成之后一个 Maven 工程便创建完成了,接下来需要导入相关依赖。

2、导入依赖

在新建项目的pom.xml文件中添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
</dependencies>

注:这里是以 mysql 数据库为例,如果使用其它数据库,请自行导入相关的驱动。

3、创建数据库表映射的实体类及映射器接口类

由案例中的信息可知,数据库表映射的实体类为Person,下面给出实体类的完整定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package cn.frankfang.mybatis.entity;

/**
* 数据库表对应的实体类
*/
public class Person {
// 对应数据库表中的name字段
private String name;
// 对应数据库表中的age字段
private int age;

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

映射器是一些绑定映射语句的接口,而映射器接口的实例是从 SqlSession 中获得的。下面给出映射器的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package cn.frankfang.mybatis.mapper;

import cn.frankfang.mybatis.entity.Person;

import java.util.List;

public interface PersonMapper {

/**
* 查询数据库中所有的Person信息
* @return
*/
List<Person> selectList();
}

3、使用配置文件方式实现功能

从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。下面给出mybatis-config.xml配置文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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/datasource
?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone = GMT"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/frankfang/mybatis/mapper/PersonMapper.xml"/>
</mappers>
</configuration>

注:其中数据库的驱动全类名、URL、用户名和密码根据实际情况进行填写,这里仅供参考。另外,XML头部的声明用来验证XML文档的正确性。environment元素体中包含了事务管理和连接池的配置。mappers元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。下面给出PersonMapper.xml文件的内容:

1
2
3
4
5
6
7
8
9
<?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="cn.frankfang.mybatis.mapper.PersonMapper">

<select id="selectList" resultType="cn.frankfang.mybatis.entity.Person">
SELECT * FROM person
</select>

</mapper>

注:select标签中的id要与映射器接口中的方法名称对应,resultType表示查询结果映射类型。

若需获取关于XML配置文件和XML映射文件的完整信息,请参阅:XML配置文件XML映射文件

在完成配置文件的编写之后,便可以在项目中使用Mybatis框架,下面给出调用框架实现查询功能的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package cn.frankfang.mybatis;

import cn.frankfang.mybatis.entity.Person;
import cn.frankfang.mybatis.mapper.PersonMapper;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.util.List;

public class Demo01 {
public static void main(String[] args) {
// 1.获取配置文件
String resource = "cn/frankfang/mybatis/mybatis-config.xml";
InputStream is = Demo01.class.getClassLoader().getResourceAsStream(resource);
// 2.创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// 3.从SqlSessionFactory中获取SqlSession
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
// 3.1 通过动态代理创建PersonMapper接口的增强实现类
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
// 3.2 调用PersonMapper接口查询并获取结果
List<Person> list = personMapper.selectList();
for (Person person : list) {
System.out.println(person);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

注意:Maven在打包时并不会将类路径下的XML文件加入进来,这将导致项目运行时无法获取配置文件而出错,因此要在pom.xml文件中加入以下内容:

1
2
3
4
5
6
7
8
9
10
11
<build>
<!-- 重新指明资源文件位置 -->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>

项目的完整结果如下:

项目结构-配置文件方式

运行项目,结果如下:

1
2
Person{name='Amy', age=22}
Person{name='Frank', age=20}

可以看到控制台已经打印出从数据库中查询出的结果。

4、使用配置类和注解方式实现功能

如果你更愿意直接从 Java 代码而不是 XML 文件中创建配置,或者想要创建你自己的配置建造器,MyBatis 也提供了完整的配置类,提供了所有与 XML 文件等价的配置项。

首先需要实现java.sql.DataSource接口,实现类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package cn.frankfang.mybatis.impl;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

public class PersonDataSource implements DataSource {
@Override
public Connection getConnection() throws SQLException {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return DriverManager
.getConnection("jdbc:mysql://localhost:3306/datasource" +
"?useUnicode=true&characterEncoding=utf-8" +
"&useSSL=false&serverTimezone = GMT", "username", "password");
}

@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}

@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}

@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}

@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}

@Override
public void setLogWriter(PrintWriter out) throws SQLException {

}

@Override
public void setLoginTimeout(int seconds) throws SQLException {

}

@Override
public int getLoginTimeout() throws SQLException {
return 0;
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}

接下来删除mybatis-config.xmlPersonMapper.xml文件,并改写PersonMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package cn.frankfang.mybatis.mapper;

import cn.frankfang.mybatis.entity.Person;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface PersonMapper {

/**
* 查询数据库中所有的Person信息
* @return
*/
@Select("select * from person")
List<Person> selectList();
}

注:通过注解方式可以直接将SQL语句添加在注解上,无需编写XML映射文件。

之后编写调用框架实现查询功能的代码,完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package cn.frankfang.mybatis;

import cn.frankfang.mybatis.impl.PersonDataSource;
import cn.frankfang.mybatis.entity.Person;
import cn.frankfang.mybatis.mapper.PersonMapper;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import java.util.List;

public class Demo01 {
public static void main(String[] args) {
// 1.添加配置信息
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development",
transactionFactory, new PersonDataSource());
Configuration configuration = new Configuration(environment);
configuration.addMapper(PersonMapper.class);
// 2.创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(configuration);
// 3.从SqlSessionFactory中获取SqlSession
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
// 3.1 通过动态代理创建PersonMapper接口的增强实现类
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
// 3.2 调用PersonMapper接口查询并获取结果
List<Person> list = personMapper.selectList();
for (Person person : list) {
System.out.println(person);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

项目的完整结构如下:

项目结构-配置类及注解方式

运行项目,结果如下:

1
2
Person{name='Amy', age=22}
Person{name='Frank', age=20}

可以看到,通过配置类和注解的方式同样可以实现查询的功能,具体使用哪种方法可根据实际情况决定。

若需获取更多信息,请参阅:Mybatis入门