首页 > 技术文章 > Mybatis简介

IUbanana 2017-07-24 16:15 原文

一、简介

MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀持久层框架。
Mybatis前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录。
 

1.1 Mybatis的功能架构分为三层:

1) API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
2) 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
3) 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。 
 

1.2 Mybatis安装配置

  • 下载jar包(核心类库):mybatis-3.4.4.jar
  • 参考文档:mybatis-3.4.4.pdf
  • API文档:mybatis-3.4.4-javadoc.jar
  • 源代码:mybatis-3.4.4-source.jar
 

1.3 Mybatis特点

(1)SQL语句与代码分离
优点:便于管理维护
缺点:不便于调试,可能需要借助日志工具(log4j)
(2)用标签控制动态SQL的拼接
优点:用标签代替便编写拼接的逻辑代码
缺点:拼接复杂的SQL语句时,没有代码灵活,比较复杂
(3)结果集与Java对象的自动映射
优点:保证名称相同即可自动映射
缺点:依赖于相应的SQL语句
(4)编写原生SQL(半自动)
优点:接近JDBC,很灵活
缺点:对SQL语句依赖很高,因此不方便数据库移植
 

1.4 Mybatis优点

  • 只需要在配置文件Mapper.xml中编写SQL语句,在应用程序中就可以通过面向对象方法访问数据库
  • 在JDBC访问过程中有大量的checked异常被包装成Mybatis的Runtime异常,从而不要求程序必须处理所有异常

二、Mybatis基本用法

2.1 Mybatis一般操作步骤
1). 开发持久化类PO和对应持久化操作的Mapper.xml配置文件,在配置文件中定义操作持久化类对应数据库表格的SQL语句。
2). 获取SqlSessionFactory
3). 获取SqlSession
4). 用面向对象方式操作数据库
5). 关闭事务,关闭SqlSession
 
实例:
//读取mybatis的配置文件
InputStream inputStream = Resources.getResourcesAsStream("mybatis-config.xml");
//初始化mybatis,穿件SqlSessionFactory类的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建能执行映射文件中SQL语句的sqlSession
SqlSession session = sessionFactory.openSession();

 

初始化Mybatis的过程:输入数据流 -> Configuration对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1)调用SqlSessionFactoryBuilder对象的build(inputStream)方法,SqlSessionFactoryBuilder会根据输入流等信息创建XMLConfigBuilder对象
2)调用XMLConfigBuilder对象的parse()方法,解析返回Configuration文件
3)SqlSessionFactoryBuilder根据返回的Configuration对象创建一个DefaultSessionFactory对象并返回
4)客户端根据返回的DefaultSessionFactory对象,可以使用

 

调用SQL语句时,一般先编写相应的XXMapper接口,类名与XXMapper.xml配置文件中namespace一致,方法名与某个SQL语句的id一致、参数返回值类型等也要一致;
调用时,直接通过动态代理该接口中的方法调用配置文件中的SQL语句。
 
Mybatis 动态代理源码分析
1. Mybatis 如何通过接口找到配置文件中对应的信息,而且直接调用接口的方法
(实例:项目文件MessageDao中的iMessage.queryMessageList(); 进行了直接调用,执行了没有实现类的接口的方法)
MapperProxy implements InvocationHandler 类中方法:
MapperProxy.invoke() -> Proxy.newInstance(类加载器,接口,MapperProxy对象)
 
项目中 sqlSession.getMapper() == Proxy.newInstance()
即 IMessage iMessage = sqlSession.getMapper(IMessage.class); == Proxy.newInstance(IMessage.class)
其中的iIMessage对象并不是IMessage实现类的对象,而是是一个动态代理实例 iMessage.queryMessageList(message); == MapperProxy.invoke()
执行本条语句时不会直接执行queryMessageList(),而是触发了MapperProxy.invoke()
MapperProxy.invoke()会在配置文件中查找相应的配置信息
具体查找方法:接口名<->namespace 方法名<->id,即接口全名称.方法名 == namespace.id
因此,接口方法定义时的参数类型和返回值类型要与相应配置文件中的配置信息对应
-----------------------------------------------
Java代码:
package com.imooc.dao;
public interface IMessage {
public List<Message> queryMessageList(Message message);
}
------------------------------------------------
Message.xml配置文件:
<!--namespace对应接口全名称-->
<mapper namespace="com.imooc.dao.IMessage">
<resultMap type="com.imooc.bean.Message" id="MessageResult">
<id column="ID" jdbcType="INTEGER" property="id"/>
<result column="COMMAND" jdbcType="VARCHAR" property="command"/>
<result column="DESCRIPTION" jdbcType="VARCHAR" property="description"/>
<result column="CONTENT" jdbcType="VARCHAR" property="content"/>
</resultMap>
<!-- 查找到id与接口方法名一致的id-->
<select id="queryMessageList" parameterType="com.imooc.bean.Message" resultMap="MessageResult">
select <include refid="columns"/> from MESSAGE
<where>
<!-- 如果test内的条件满足,在sql语句上拼接标签内容 -->
<if test="command != null and !&quot;&quot;.equals(command.trim())">
and COMMAND=#{command}
</if>
<if test="description != null and !&quot;&quot;.equals(description.trim())">
and DESCRIPTION like '%' #{description} '%'
</if>
</where>
</select>
</mapper>
------------------------------------------------
IMessage iMessage = Proxy.newInstance(IMessage.class)
因为Mybatis在getMapper()已经利用泛型进行了类型强转,所以可以用iMessage接动态代理的实例
getMapper():1)根据接口和代理类创建代理实例;2)根据泛型将代理实例类型强转为接口类型
结论:iMessage.queryMessageList(parameter) = sqlSession.selectList(namespace,id,parameter)
 
2.invoke()方法如何通过代理实例的方法运行配置文件中相应的SQL语句 (反射)
invoke()实现了InvocationHandler接口,通过反射找到接口全名称与方法名,
 
 
-----------------------
个人总结:
  • mybatis-config.xml:根配置文件,配置Mybatis环境(数据库、连接池、数据源);管理导入加载其他持久化类对应的资配置文件XXMapper.xml;
  • 持久化类:按对应数据库表格内容定义
  • XXMapper.xml: 对应持久化类SQL语句管理
  • Dao层:对相应持久化类操作的DAO类,定义相关对数据库操作的方法,上层可通过直接调用其方法完成对数据库的操作
-----------------------

 

推荐阅读