MyBatis学习笔记(一):MyBatis 架构及运作流程
目录
MyBatis学习笔记(一):MyBatis 架构及运作流程
1. MyBatis 简介
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis并不是一个完整的ORM(Object Relational Mapping,对象关系映射)框架,其官方首页介绍如下:
|
而在其官方文档中介绍“What is MyBaits”中说到:
ORM是Object和Relation之间的映射,包括Object->Relation和Relation->Object两方面。Hibernate是个完整的ORM框架,而MyBatis完成的是Relation->Object,也就是其所说的data mapper framework。关于ORM的一些设计思路和细节可以参见Martin Flow《企业应用架构模式》一书中的ORM章节,MyBatis并不刻意于完成ORM(对象映射)的完整概念,而是旨在更简单、更方便地完成数据库操作功能,减轻开发人员的工作量,我想这对于应用系统来说也是最实用的,相信用Hibernate的都受过它的痛苦,而用过MyBatis的都会感觉它很简捷轻松。 |
2. MyBatis 特点
根据 MyBatis 官方文档(http://www.mybatis.org/mybatis-3/zh/index.html)介绍:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。
用xml文件构建SqlSessionFactory实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但你可以使用任何Reader实例,包括用文件路径或file://开头的url创建的实例。MyBatis有一个实用类----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。
创建SqlSessionFactory实例的例子如下:通过SqlSession就结合映射文件就能实现Java对象持久化到数据库。
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class DBTools
{
public static SqlSessionFactory sessionFactory;
static
{
try
{
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis.cfg.xml");
//构建sqlSession的工厂
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
catch (Exception e)
{
e.printStackTrace();
}
}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession()
{
return sessionFactory.openSession();
}
}
Mybatis有哪些特点?
-
简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
-
灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
-
解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
-
提供映射标签,支持对象与数据库的ORM字段关系映射。
-
提供对象关系映射标签,支持对象关系组建维护。
-
提供xml标签,支持编写动态sql。
3. MyBatis 架构
下面是从功能流程层次描述MyBatis的整体架构图,可分为三层:
- 接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
- 核心层:负责具体的配置解析、参数处理、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
4. MyBatis 总体流程
根据前面的介绍,相信读者已经对MyBatis有了基本的认识,那么,使用MyBatis实现Java对象(Java Bean)— 数据库之间的增删改查的总体流程是怎样的呢?
步骤1:准备阶段一
既然要实现Java对象—数据库记录的增删改查,那么,首先必须有一个就绪状态的数据库,如MySql;其次,要有一个连接数据库的驱动,如mysql-connector-java;当然还需要MyBatis,如mybatis-3.4.6。
步骤2:准备阶段二
MyBatis 实现的是什么功能呢?本质上就是:1.将一个Java对象持久化到数据库中,作为一条记录存储;2. 查询数据库记录,并将它转化为一个Java对象;3. 删除、修改就不必多说了。既然如此,什么样的Java对象便于存储于数据库呢?当然是Java Bean,一个包含多个属性及其访问器(set方法)、修改器(get方法)的类,如下例子:
public class UserBean implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
public UserBean(Integer id, String username)
{
super();
this.id = id;
this.username = username;
}
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;
}
@Override
public String toString()
{
return "UserBean [id=" + id + ", username=" + username + "]";
}
}
这样的Java Bean可以完美的对应数据库的表记录,如表t_user:
create table t_user(
id int primary key auto_increment,
username varchar(20),
);
在数据库中的存储:
鉴于上述说明,还需要准备一个Java Bean类,数据库中创建一个与之对应的表。
步骤3:准备阶段三
根据MyBatis的结构可以看出,用户调用的是接口,接口中不涉及具体的sql操作,但是,这些接口必须以某种方式与具体的sql对应起来,即所谓的映射(Mapping),具体如何实现呢?——需要一个接口类和一个映射配置文件。
如下所示是一个操作User的接口,定义了insert、update、select三个方法。
public interface UserMapper
{
/**
* 新增用戶
* @param user
* @return
* @throws Exception
*/
public int insertUser(UserBean user) throws Exception;
/**
* 修改用戶
* @param user
* @param id
* @return
* @throws Exception
*/
public int updateUser(UserBean user, int id) throws Exception;
/**
* 根据id查询用户信息
* @param id
* @return
* @throws Exception
*/
public UserBean selectUserById(int id) throws Exception;
}
与接口对应的是一个xml文件,如下所示:
- resultMap定义返回结果集;
- 在各种标签中的id属性必须和接口中的方法名相同 , id属性值必须是唯一的,不能够重复使用。parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型;
- useGeneratedKeys:( 仅 对 insert 有 用 ) 这 会 告 诉 MyBatis 使 用 JDBC 的getGeneratedKeys 方法来取出由数据(比如:像 MySQL 和 SQLServer 这样的数据库管理系统的自动递增字段)内部生成的主键。默认值: false;
- keyProperty: (仅对 insert有用)标记一个属性, MyBatis 会通过 getGeneratedKeys或者通过 insert 语句的 selectKey 子元素设置它的值。默认:不设置;
- #{}中的内容,为占位符,当参数为某个JavaBean时,表示放置该Bean对象的属性值。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yingshulan.mybatis.mybatis_learning.UserMapper">
<!-- 自定义返回结果集 -->
<resultMap id="userMap" type="UserBean">
<id property="id" column="id" javaType="java.lang.Integer"></id>
<result property="username" column="username" javaType="java.lang.String"></result>
</resultMap>
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (username) values (#{username})
</insert>
<update id="updateUser" >
update t_user set username=#{username} where id=#{id}
</update>
<select id="selectUserById" parameterType="int" resultMap="userMap">
select * from t_user where id=#{id}
</select>
</mapper>
步骤4:加载解析配置
根据前面的介绍,每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。这个配置文件中应该包含哪些东西呢?
- Java Bean的类路径或者包名,本例为UserBean,不必多解释;
- MyBatis运行环境:MyBatis实现Java对象的SQL操作必须知道数据库的配置,driver、url、username、password等;
- Mappers:步骤3中的接口(UserMapper.java)和接口与sql的映射关系文件(UserMapper.xml),这个文件很关键,自然是要加载的。
综上所述,mybatis.cfg.xml配置文件示例如下:
<?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>
<!-- 为JAVA Bean起类别名 -->
<typeAliases >
<!-- 别名方式1,一个一个的配置 type中放置的是类的全路径,alias中放置的是类别名
<typeAliase type="com.cy.mybatis.beans.UserBean" alias="UserBean"/> -->
<!-- 别名方式2,自动扫描,将JAVA类的类名作为类的类别名 -->
<package name="com.yingshulan.mybatis.mybatis_learning"/>
</typeAliases>
<!-- 配置mybatis运行环境 -->
<environments default="cybatis">
<environment id="cybatis">
<!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 -->
<transactionManager type="JDBC" />
<!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
<!-- POOLED 表示支持JDBC数据源连接池 -->
<!-- UNPOOLED 表示不支持数据源连接池 -->
<!-- JNDI 表示支持外部数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mysql?useUnicode=true&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 告知映射文件方式1,一个一个的配置
<mapper resource="com/cy/mybatis/mapper/UserMapper.xml"/>-->
<!-- 告知映射文件方式2,自动扫描包内的Mapper接口与配置文件 -->
<package name="com/yingshulan/mybatis/mybatis_learning"/>
</mappers>
</configuration>
加载配置文件mybatis.cfg.xml,并解析,进而创建SqlSessionFactory实例,再创建能执行映射文件中sql的sqlSession。如下代码:
public class DBTools
{
public static SqlSessionFactory sessionFactory;
static
{
try
{
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis.cfg.xml");
//构建sqlSession的工厂
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
catch (Exception e)
{
e.printStackTrace();
}
}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession()
{
return sessionFactory.openSession();
}
}
步骤5:通过sqlSession调用接口
- SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
- SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
- 结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。
调用接口:insertUser()
/**
* 新增用户
*/
private static void insertUser()
{
SqlSession session = DBTools.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
UserBean user = new UserBean("zhangsan");
try
{
mapper.insertUser(user);
System.out.println(user.toString());
// 执行SQL
session.commit();
}
catch (Exception e)
{
e.printStackTrace();
session.rollback();
}
}
根据接口和sql的映射配置文件—UserMapper.xml 可以知道该接口(接口名与ID对应)对应的SQL语句和参数。以接口insertUser()为例,UserMapper.xml 对应的配置如下:
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (username) values (#{username})
</insert>
执行SQL:Flushes batch statements and commits database connection.
// 执行SQL
session.commit();
如果接口有返回值,则将数据库返回的结果根据映射配置进行转换,然后返回,本例中insertUser()没有返回值。
参考文献:
1. 博客:https://www.cnblogs.com/mengheng/p/3739610.html