MyBatis之基础使用

mybatis 之基础使用

mybatis 独立运行

安装依赖

建立maven项目,导入mybatis的jar包

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4-snapshot</version>
</dependency>

创建配置文件的相关类

创建一个全局配置文件,这里面是对MyBatis的核心行为的控制,比如mybatis-config.xml,放在resources资源文件夹下。

这里面只定义了数据源和Mapper映射器路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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>
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/><!-- 单独使用时配置成MANAGED没有事务 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>

</configuration>

创建db.properties 配置数据库相关信息,与 mybatis-config.xml 在同级目录下

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/dxy_test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=Toor@123

创建映射器文件:UserMapper.xml,位于resources/mapper文件夹下,通常来说一张表应一个,需要会在这个里面配置增删改查的SQL语句,以及参数和返回的结果集的映射关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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.dxysun.mybatis.mapper.UserMapper">

<resultMap id="BaseResultMap" type="com.dxysun.mybatis.domain.User">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="userName" column="user_name" />
<result property="realName" column="real_name" jdbcType="VARCHAR" />
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="age" column="age" jdbcType="INTEGER"/>
<result property="dId" column="d_id" jdbcType="INTEGER"/>
</resultMap>

<select id="selectUserByName" resultMap="BaseResultMap">
select
*
from t_user where user_name = #{userName}
</select>
</mapper>

数据表t_user结构

1
2
3
4
5
6
7
8
9
CREATE TABLE `t_user` (
`id` int NOT NULL AUTO_INCREMENT,
`user_name` varchar(20) DEFAULT NULL,
`real_name` varchar(30) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`age` int DEFAULT NULL,
`d_id` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

com.dxysun.mybatis.domain 包下创建实体类

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public class User implements Serializable
{
private Integer id;

private String userName;

private String realName;

private String password;

private Integer age;

private Integer dId;

public Integer getId()
{
return id;
}

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

public String getUserName()
{
return userName;
}

public void setUserName(String userName)
{
this.userName = userName;
}

public String getRealName()
{
return realName;
}

public void setRealName(String realName)
{
this.realName = realName;
}

public String getPassword()
{
return password;
}

public void setPassword(String password)
{
this.password = password;
}

public Integer getAge()
{
return age;
}

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

public Integer getDId()
{
return dId;
}

public void setDId(Integer dId)
{
this.dId = dId;
}

@Override
public String toString()
{
return "User{" + "id=" + id + ", userName='" + userName + '\'' + ", realName='" + realName + '\''
+ ", password='" + password + '\'' + ", age=" + age + ", dId=" + dId + '}';
}
}

使用StatementID执行查询

MyBatis是怎样执行一个查询呢?

既然MyBatis的目的是简化JDBC的操作,那么它必须要提供一个可以执行增删改查的对象,这个对象就是SqlSession接口,我们把它理解为跟数据库的一个连接,或者一次会话。

Sq|Session怎么创建呢?

因为数据源、MyBatis核心行为的控制(例如是否开启缓存)都在全局配置文件中,所以必须基于全局配置文件创建。这里它不是直接new出来的,而是通过一个工厂类创建的。

所以整个查询的流程就是这样的(如下代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void test0() throws Exception
{
// 1.获取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.加载解析配置文件并获取SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3.根据SqlSessionFactory对象获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 4.通过SqlSession中提供的 API方法来操作数据库
List<User> list = sqlSession.selectList("com.dxysun.mybatis.mapper.UserMapper.selectUserByName", "zhangsan");
System.out.println("查询结果");
for (User user : list)
{
System.out.println(user);
}
// 5.关闭会话
sqlSession.close();
}

通过SqlSession接口上的方法传入StatementID来执行Mapper映射器中的SQL,从而进一步执行查询。

不过,这样的调用方式还是会存在一些问题:

(1) Statement ID是硬编码,维护起来很不方便;

(2)不能在编译时进行类型检查,如果namespace或者StatementID输错了,只能在运行的时候报错。

所以通常会使用第二种方式,也是新版的MyBatis里面推荐的方式:

定义一个Mapper接口的方式,这个接口全路径必须跟Mapper.xml里面的namespace对应起来,方法也要跟Statement ID一对应。

使用接口执行查询

定义接口

com.dxysun.mybatis.mapper包下定义接口UserMapper

1
2
3
4
5
6
7
8
9
10
11
import java.util.List;

import com.dxysun.mybatis.domain.User;

/**
* Dao 的接口声明
*/
public interface UserMapper
{
List<User> selectUserByName(String userName);
}

执行查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* MyBatis getMapper 方法的使用
*/
@Test
public void test3() throws Exception
{
// 1.获取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.加载解析配置文件并获取SqlSessionFactory对象 全局配置文件解析 映射文件解析
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3.根据SqlSessionFactory对象获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 4.通过SqlSession中提供的 API方法来操作数据库
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> list = mapper.selectUserByName("zhangsan");
System.out.println("查询结果");
for (User user : list)
{
System.out.println(user);
}
// 5.关闭会话
sqlSession.close();
}

mybatis核心

核心特性

  • SQL和代码分离,集中管理
  • 结果集映射
  • 参数映射和动态SQL
  • 重复SQL的提取
  • 缓存管理
  • 插件机制

核心对象

mybatis的核心对象主要为 SqISessionFactoryBuiler,SqlSessionFactory, SqlSession和Mapper对象。

SqlSessionFactoryBuiler

首先是SqlSessionFactoryBuiler,它是用来构建SqlSessionFactory的,而SqlSessionFactory只需要一个,所以只要构建了这一个SqlSessionFactory,它的使命就完成了,也就没有存在的意义了,所以它的生命周期只存在于方法的局部。

SqlSessionFactory

SqlSessionFactory是用来创建SqlSession的,每次应用程序访问数据库,都需要创建一个会话。因为我们一直有创建会话的需要,所以SqlSessionFactory应该存在于应用的整个生命周期中(作用域是应用作用域)。创建SqlSession只需要一个实例来做这件事就行了,否则会产生很多的混乱,和浪费资源,所以应该采用单例模式。

SqISession

SqlSession是一个会话,因为它不是线程安全的,不能在线程间共享,所以在请求开始的时候创建一个SqlSession对象,在请求结束或者说方法执行完毕的时候要及时关闭它(一次请求或者操作中)。

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

Mapper

Mapper(实际上是一个代理对象),是从SqlSession中获取的,它的作用是发送SQL来操作数据库的数据,它应该在一个SqlSession事务方法之内。

Mapper是一些绑定映射语句的接口。虽然从技术层面上来讲,任何Mapper实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是Mapper实例的最合适的作用域。 也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。

最后总结如下

核心配置

官网配置说明,下面简单总结下

configuration

configuration是整个配置文件的根标签,实际上也对应着MyBatis里面最重要的配置类Configuration,它有很多的属性,跟其他的子标签也能对应上。

properties

第一个一级标签是prooerties,用来配置参数信息,比如最常见的数据库连接信息。

为了避免直接把参数写死在xml配置文件中,我们可以把这些参数单独放在properties文件中,用properties标签引入进来,然后在xml配置文件中用${}引用就可以了。

可以用resource引用应用里面的相对路径,也可以用url指定本地服务器或者网络的绝对路径。

settings

setttings里面是MyBatis的一些核心配置,会改变 MyBatis 的运行时行为。

typeAliases

TypeAlias是类型的别名,跟Linux系统里面的alias一样,主要用来简化类名全路径的拼写。比如我们的参数类型和返回值类型都可能会用到我们的Bean,如果每个地方都配置全路径的话,那么内容就比较多,还可能会写错。我们可以为自己的Bean创建别名,既可以指定单个类,也可以指定一个package,自动转换。

typeHandlers

由于Java类型和数据库的JDBC类型不是一对应的(比如String与varchar、 char、text),所以我们把Java对象转换为数据库的值,和把数据库的值转换成Java对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。

当参数类型和返回值是一个对象的时候,我们没有做任何的配置,为什么对象里面的个String属性,可以转换成数据库里面的varchar字段?
这是因为MyBatis已经内置了很多TypeHandler(在type包下),它们全部全部注册在TypeHandlerRegistry中,他们都继承了抽象类BaseTypeHandler,泛型就是要处理的Java数据类型。这个也是为什么大部分类型都不需要处理。当我们查询数据和登记数据,做数据类型转换的时候,就会自动调用对应的TypeHandler的方法。

如果我们需要自定义一些类型转换规则,或者要在处理类型的时候做一些特殊的动泡学作,就可以编写自己的TypeHandler,跟系统自定义的TypeHandler一样,继承抽象类BaseTypeHandler<T>,有4个抽象方法必须实现,可以分成两类:set方法从Java类型转换成JDBC类型的,get方法是从JDBC类型转换成Java类型的。

objectFactory

当我们把数据库返回的结果集转换为实体类的时候,需要创建对象的实例,由于我们不知道需要处理的类型是什么,有哪些属性,所以不能用new的方式去创建。只能通过反射来创建。

在MyBatis里面,它提供了一个工厂类的接口,叫做ObjectFactory,专门用来创建对象的实例(MyBatis封装之后,简化了对象的创建)。

ObjectFactory有一个默认的实现类DefaultObjectFactory。创建对象的方法最终都调用了instantiateClass(),这里面能看到反射的代码。

默认情况下,所有的对象都是由DefaultObjectFactory创建。

如果想要修改对象工厂在初始化实体类的时候的行为,就可以通过创建自己的对象工厂,继承DefaultObjectFactory来实现(不再需要实现ObjectFactory接口)。

plugins

插件是MyBatis的一个很强大的机制。跟很多其他的框架一样,MyBatis预留了插件的接口,让MyBatis更容易扩展。

默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

SqlSession是对外提供的接口。而SqlSession增删改查的方法都是由Executor完成的。
Executor是真正的执行器的角色,也是实际的SQL逻辑执行的开始,MyBatis中又把SQL的执行,按照过程,细分成了三个对象:ParameterHandler处理参数,StatementHandler执行SQL,StatementHandler处理结果集。

environments

environments标签用来管理数据库的环境,比如我们可以有开发环境、测试环境、生产环境的数据库。可以在不同的环境中使用不同的数据库地址或者类型。

一个environment标签就是一个数据源,代表一个数据库。它的下面有两个关键的标签,一个是事务管理器,一个是数据源。

transactionManager

如果配置的是JDBC,则会使用Connection对象的commit()、rollback()、close() 管理事务。

如果配置成MANAGED,会把事务交给容器来管理,比如JBOSS,Weblogic。如果是Spring + MyBatis,则没有必要配置,因为我们会直接在applicationContext.xml里面配置数据源和事务,覆盖MyBatis的配置。

数据源(DataSource)

数据源,顾名思义,就是数据的来源,它是对数据库连接的一个抽象。一个数据源就对应一个数据库。一般的数据源都会包括连接池管理的功能,所以很多时候也把DataSource直接称为连接池,准确的说法应该是:带连接池功能的数据源。

除了连接池之外,大家应该也听过很多其他的池,比如线程池,内存池,对象池,这种池化技术达到的目的基本上一样的。

如果没有连接池,那么每一个用户、每一次会话连接数据库都需要直接创建和释放连接,这个过程是会消耗的一定的时间的,并且会消耗应用和服务器的性能。

当我们没有使用连接池的时候,客户程序得到的连接是一个物理连接,我们调用close()方法会把这个连接真正地关闭。

如果采用连接池技术,在应用程序里面关闭连接的时候,物理连接没有被真正关闭掉,只是回到了连接池里面。

从这个角度来考虑,一般的连接池都会有初始连接数、最大连接数、回收时间等等这些参数,提供提前创建/资源重用/数量控制/超时管理等等这些功能。

MyBatis自带了两种数据源,UNPOOLED和POOLED。也可以配置成其他数据库,比如C3P0、Hikari等等。市面上流行的数据源,一般都有连接池功能。

在跟Spring集成的时候,事务和数据源都会交给Spring来管理,不再使用MyBatis配置的数据源。

mappers

mappers标签配置的是映射器,也就是Mapper.xml的路径。这里配置的目的是让MyBatis在启动的时候去扫描这些映射器,创建映射关系。

Mapper.xml映射配置文件

映射器里面最主要的是配置了SQL语句,也解决了我们的参数映射和结果集映射的问题。

一共有8个标签:

<cache> 给定命名空间的缓存配置(是否开启二级缓存)

<cache-ref> 其他命名空间缓存配置的引用

<resultMap> 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象

<sql> 可被其他语句引用的可重用语句块

<insert> 映射插入语句

<update> 映射更新语句

<delete>映射删除语句

<select> 映射查询语句

具体的可以查看官网 http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html

动态sql

动态 SQL 是 MyBatis 的强大特性之一,主要有以下几个标签

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

更多详细信息查看官网 https://mybatis.org/mybatis-3/zh/dynamic-sql.html

参考

mybatis官网

github地址

MyBatis-Spring

打赏

请我喝杯咖啡吧~

支付宝
微信