Mybatis复习

<1>为什么使用mybatis框架
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
使用mybatis框架来替代原始JDBC的开发。mybatis把连接资源放在内部,想要用直接拿,用完还回来即可,有效的解决了JDBC频繁的创建、释放连接资源。而且我们使用mybatis框架,当sql语句需要发生改变的,不需要改变JAVA代码,只需要更改一下配置文件即可。
<2>mybatis执行的流程

<3>mybatis入门
1 | <dependencies> |
1 | package com.liu.domain; |
mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。
1 |
|
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 XML 配置文件的详细内容,这里先给出一个简单的示例:
1 |
|
当然,还有很多可以在 XML 文件中配置的选项,上面的示例仅罗列了最关键的部分。 注意 XML 头部的声明,它用来验证 XML 文档的正确性。environment 元素体中包含了事务管理和连接池的配置。
进行测试是否成功
1 |
|
运行结果展示:

<4>mybatis增删改查
如果通过上述代码来写的话,可以发现有很多的代码是重复的。所以我们使用JUnit的@Before来创建sqlSession对象以及通过@After来关闭sqlSession,释放资源。
1 | import com.liu.domain.User; |
<5>mybatis的Dao层实现
通过上述mybatis快速入门你会发现,我根本就没编写Dao层呀。到时候我该如何和service层进行交互呢?但这也发现了mybatis的神奇之处:mybatis不需要Dao层就可以实现增删改查。接下来让我们看一看如何使用mybatis来实现Dao层。
第一种:传统方式实现
即首先创建一个UserDao接口,在接口中编写业务方法。通过UserDaoImpl这个类来实现UserDao的方法,从而把数据返回给Service层的UserServiceImpl。
UserDao接口:
1 | public interface UserDao { |
UserDaoImpl接口实现:
1 | public class UserDaoImpl implements UserDao { |
第二种:代理开发模式
采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper 接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的全限定名相同
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
例如:
UserDao接口:
1 | public interface UserDao { |
mapper.xml映射文件:
1 | <mapper namespace="com.liu.dao.UserDao"> |
UserServiceImpl测试:
1 | public class UserServiceImpl { |
结果:

<6>mybatis的核心配置文件
点击可直接进入官网详细查看:
configuration(配置)
-
properties:用于读取properties配置文件
1
2<!--加载属性文件-->
<properties resource="jdbc.properties"/>1
2
3
4=com.mysql.cj.jdbc.Driver
=jdbc:mysql:///stu?useSSL=false&useUnicode=true&characterEconding=UTF-8&allowPublicKeyRetrieval=true
=root
=131411 -
settings:一般我们用来配置日志文件
配置使用log4j日志文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#���ȼ�ΪDEBUG����־��Ϣ�����console��file������Ŀ�ĵأ�console��file�Ķ���������Ĵ���
=DEBUG,console
#����̨������������
= org.apache.log4j.ConsoleAppender
= System.out
=DEBUG
= org.apache.log4j.PatternLayout
=[%c]-%m%n
#��־�������
=DEBUG
=DEBUG
=DEBUG
=DEBUG
=DEBUG -
一般用于给类起别名
1
2
3
4
5<!--给包中的类注册别名-->
<typeAliases>
<typeAlias type="com.liu.pojo.User" alias="User"/>
<typeAlias type="com.liu.pojo.Orders" alias="Orders"/>
</typeAliases> -
一般使用自带的类型处理器,但是当想对数据进行更改操作时可以更改重写类型处理器
eg:数据库中的DateTime类型想输出时为Date
-
插件有很多,可以配置一个很常用的分页查询插件
mybatis-config.xml配置如下:
1
2
3
4
5
6<!--配置分页助手插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
</plugins>但是这个插件需要引入坐标
1
2
3
4
5
6
7
8
9
10<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>使用的时候只需要写一行代码
1
2//设置分页相关参数 当前页+每页要显示的个数
PageHelper.startPage(1,3); environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
一般我们配置的都是JDBC事务管理器
dataSource(数据源)
dataSource配置获取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<!--数据源环境-->
<environments default="development">
<!--配置一个id为development的环境-->
<environment id="development">
<!--使用JDBC事务-->
<transactionManager type="JDBC"/>
<!--数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>-
这个几乎没用过
-
超级重要!!!用来加载Mapper.xml文件的!!!
1
2
3
4
5<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
<mapper resource="OrdersMapper.xml"/>
</mappers><7>mybatis的mapper文件的配置
最重要的就是下面这几块了!!!
1 | <mapper namespace="com.liu.dao.UserDao"> |
这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。
1 | <!--Sql片段的抽取--> |
| 属性 | 描述 |
|---|---|
| id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
| parameterType | 描述将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
| resultType | **期望从这条语句中返回结果的类全限定名或别名**。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。 |
| resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。 |
| resultSets | 这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 |
eg:在mapper.xml配置文件中写入
1 | <!--查询所有--> |
| 属性 | 描述 |
|---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
1 | <!--插入新User--> |
| 属性 | 描述 |
|---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
1 | <!--更改用户信息--> |
| 属性 | 描述 |
|---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
1 | <!--删除用户--> |
默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。
<8>mybatis的动态SQL
动态SQL:根据不同条件拼接 SQL 语句
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。
1 | <!--动态SQL--> |
测试:
1 | public static void main(String[] args) throws IOException { |

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
1 | <!--通过多个id查询用户数据--> |
测试:
1 | public static void main(String[] args) throws IOException { |

<9>mybatis的多表查询
接下来的就是重点啦~
学会使用了简单的Crud,现在有一个问题出现在我们面前。上述说的crud都是单表的操作,那么双表的操作该如何用mybatis实现呢?
多表操作无非就是三种:一对一,一对多,多对多
一对一我们应该要如何实现呢?
这里是关于用户和订单的业务,我们要查询每个订单的用户都是谁。我们该如何去做呢?
1.**这时我们需要把要查询的用户** 给封装成订单的一个属性并生成get/set方法
1 | public class Orders { |
*2.**创建OrdersDao*,并且写一个查询抽象方法。
1 | public interface OrdersDao { |
*3.**在OrdersMapper.xml*中进行配置:
这里的结果集我们需要自己进行封装,所以我们不能用resultType
我们需要使用resultMap进行自己封装
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。
resultMap包含的元素:
1 | <!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性--> |
1 | <resultMap id="findUserOrder" type="Orders"> |
上面的配置使用逻辑不好,请看下面的逻辑
1 | <resultMap id="findUserOrder" type="Orders"> |
**4.**测试:
1 | //一对一多表查询 |

一对多的过程与一对一的过程只差了一点点:
业务:一个User有多个Order,要查询User的Order
**1.**我们首先在User里要封装一个list集合,这个集合的泛型是Order类型
1 | package com.liu.pojo; |
*2.**在UserDao*中创建一个方法
1 | public interface UserDao { |
*3.**在UserMapper.xml*中进行配置
因为orders属性是一个集合,所以要用到resultMap的collection标签:
1 | <!-- 集合中的property须为oftype定义的pojo对象的属性--> |
配置如下:
1 | <resultMap id="userFindOrders" type="User"> |
**4.**进行Test测试
1 | //一对多查询 |

多对多的查询与一对多几乎是一样的,除了多了一个中间表
业务介绍:我们现在有一张user表,一张role表,还有一张连接表userrole。现在我们需要知道User是什么职位的。
1.首先封装一个list集合,一个user可能有多个role,而一个role可能有多个user。所以我们需要封装一个List,泛型为role.
Role类:
1 | package com.liu.pojo; |
User类
1 | package com.liu.pojo; |
2.在UserDao创建一个方法
1 | public interface UserDao { |
3.在UserMapper.xml进行配置
1 | <resultMap id="UserAndRole" type="User"> |
4.测试:
1 | //测试多对多查询 |
1 | [com.liu.dao.UserDao.findUserAndRoleAll]-==> Preparing: SELECT * from `user` u,role r,userrole ur where u.id=ur.userId and r.id=ur.roleId; |
<10>mybatis的注解开发
每一个框架肯定是要有注解的,所以我们需要学习注解开发来简易开发流程。
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
普通的增删改查
配置mybatis-config.xml核心配置文件:加载映射关系TODO
1 | <!--加载映射关系 TODO--> |
基本注解的使用:
1 | public interface UserDao { |
基本注解测试:
1 | public class Test01 { |
实现复杂关系映射之前我们可以在映射文件中通过配置resultMap来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
| 注解 | 说明 |
|---|---|
| @Results | 代替的是标签resultMap该注解中可以使用单个@Result注解,也可以使用@Result集合。使用格式:@Results({@Result(),@Result()})或@Results(@Result()) |
| @Resut | 代替了id标签和result标签 @Result中属性介绍: column:数据库的列名 property:需要装配的属性名 one:需要使用的@One 注解(@Result(one=@One)())) many:需要使用的@Many 注解(@Result(many=@many)())) |
| 注解 | 说明 |
|---|---|
| @One (一对一) | 代替了assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。 @One注解属性介绍: select: 指定用来多表查询的 sqlmapper使用格式:@Result(column=” “,property=””,one=@One(select=””)) |
| @Many (多对一) | 代替了collection标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。 使用格式:@Result(property=””,column=””,many=@Many(select=””)) |
1 | public interface OrdersDao { |
测试:
1 |
|
日志文件:
1 | [com.liu.dao.OrdersDao.findAllAndUser]-==> Preparing: SELECT * from orders |
UserDao中创建方法
1 | //多表查询:一对多 |
OrdersDao方法:把select *from user查到的uid传给这个方法,通过这个方法得到一些Orders,再把这些Order给封装到User的orders属性中。
1 |
|
测试:
1 | //测试一对多 |
测试日志结果:
1 | [com.liu.dao.UserDao.findUserAndRole]-==> Preparing: select *from user |
UserDao中创建方法
1 | //测试多对多 |
RoleDao方法:把select *from user查到的uid传给这个方法,通过这个方法得到一些Orders,再把这些Order给封装到User的orders属性中。
1 | public interface RoleDao { |
测试:
1 | //测试多对多 |
测试日志:
1 | [com.liu.dao.UserDao.findUserRoleAll]-==> Preparing: select *from user |
<11>mybatis总结
大家在开始学习mybatis插件的时候可以下载一个插件,可以通过这个插件就能像Spring查看方法的定义之处。


这算是第二遍学习mybatis了,还不错。过去学的东西忘了好多,但是学习过后,有的东西都加深了理解。以前很多不会的知识,现在懂了很多。要加油哦~接下来就要学习mybatis-plus,不知道这个难度如何。感觉这个应该和mybatis差距不大,毕竟是基于mybatis的。加油!!!