博客
关于我
Mybatis 快速入门(XML方式) 底层源码对象初始化过程分析
阅读量:407 次
发布时间:2019-03-06

本文共 12882 字,大约阅读时间需要 42 分钟。

导读

官网地址

https://mybatis.org/mybatis-3/zh/index.html

架构原理图

说明

mybatis配置文件

  1. SqlMapConfig.xml,此文件为mybatis的全局配置文件,配置了mybatis的运行环境等信息
  2. XXXMapper.xml,此文件作为mybatis的sql映射文件,文件中配置了操作数据库的CRUD语句。需要在SqlMapConfig.xml中加载

SqlSessionFactory

  1. 通过mybatis环境等配置信息构造SqlSessionFactory,既会话工厂

***跟底层源码查看创建SqlSessionFactory流程***

注:底层如何获取标签值,请自行研究(剧透:for循环遍历XML获取标签中的值,然后放入Map)!~

SqlSession

  1. 通过会员工厂创建SqlSession即会话,程序通过SqlSession会话接口对数据库进行CRUD操作。

Executor执行器

  mybatis底层自定义了Executor执行器接口来具体操作数据库,Executor接口有两个实现,一个是基本执行器(默认),一个缓存执行器,SqlSession底层是通过executor接口操作数据库

Mapped Statement

  他是mybatis一个底层封装对象,包装了mybatis配置信息及XXXMapper.xml映射文件等。XXXMapper.xml文件中一个个select/insert/update/delete标签对应一个Mapped Statement对象

原始JDBC代码

  原始JDBC和mybatis操作数据库数据,与上面架构图流程相对应。

public class JDBCTest {    public static void main(String[] args) {        Connection connection = null;        PreparedStatement preparedStatement = null;        ResultSet resultSet = null;        try {            // 加载数据库驱动            Class.forName("com.mysql.jdbc.Driver");            // 通过驱动管理类获取数据库链接connection = DriverManager            connection = DriverManager.getConnection(                              "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",                             "root",                               "root"                              );            // 定义sql语句 ?表示占位符            String sql = "select * from user where username = ?";            // 获取预处理 statement            preparedStatement = connection.prepareStatement(sql);                        // 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的            preparedStatement.setString(1, "王五");            // 向数据库发出 sql 执行查询,查询出结果集            resultSet = preparedStatement.executeQuery();            // 遍历查询结果集            while (resultSet.next()) {                System.out.println(                                  resultSet.getString("id")                                   + " " +                                   resultSet.getString("username")                     );            }        } catch (Exception e) {            e.printStackTrace();        } finally {            // 释放资源            if (resultSet != null) {                try {                    resultSet.close();                } catch (SQLException e) {                    e.printStackTrace();                }            }            if (preparedStatement != null) {                try {                    preparedStatement.close();                } catch (SQLException e) {                    e.printStackTrace();                }            }            if (connection != null) {                try {                    connection.close();                } catch (SQLException e) {                    // TODO Auto-generated catch block e.printStackTrace();                }            }        }    }}

Mybatis 入门基础

表结构

 表数据

Mybatis环境搭建 

添加依赖

pom.xml

4.0.0
com.cyb
mybatis
war
0.0.1-SNAPSHOT
mybatis Maven Webapp
http://maven.apache.org
org.mybatis
mybatis
3.4.6
mysql
mysql-connector-java
8.0.20
junit
junit
4.12
mybatis

SqlMapConfig.xml

db.properties

db.driver=com.mysql.jdbc.Driverdb.url=jdbc:mysql://127.0.0.1:3306/cybdb.username=rootdb.password=root

UserMapper.xml

User.java

package com.cyb.mybatis.demo;import java.util.Date;public class User {    private int id;    private String username;    private Date birthday;    private int sex;    private String address;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public int getSex() {        return sex;    }    public void setSex(int sex) {        this.sex = sex;    }    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }    @Override    public String toString() {        return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address="                + address + "]";    }}

MybatisDemo.java

package com.cyb.mybatis.demo;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Before;import org.junit.Test;public class MybatisDemo {    private SqlSessionFactory sqlSessionFactory;    @Before    public void init() throws Exception {        //指定全局配置文件路径        String resource = "SqlMapConfig.xml";        //加载资源文件(包括全局文件和映射文件)        InputStream inputStream = Resources.getResourceAsStream(resource);        //使用构建者模式创建SqlSessionFactory        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);    }    @Test    public void testSelect() {        //由SqlSessionFactory工厂去创建SqlSession(会话)        SqlSession sqlSession = sqlSessionFactory.openSession();        //调用SqlSession接口,去实现数据库的CRUD        User user = sqlSession.selectOne("test.queryUserById", 1);        System.out.println(user);        //释放资源        sqlSession.close();    }}

项目结构

测试

功能实现

根据用户id查询一个用户信息

根据用户名称模糊查询用户信息列表

添加用户

主键返回

select LAST_INSERT_ID()
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});

添加selectKey标签实现主键返回。

* keyProperty:指定返回的主键,存储在pojo中的哪个属性

* orderselectKey标签中的sql的执行顺序,是相对与insert语句来说。由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after。

* resultType:返回的主键对应的JAVA类型

* LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。

更新用户

删除用户

Mybatis开发Dao层

mapper代理开发方式

XML方式

使用:只需要开发Mapper接口(Dao接口)和xxxMapper约束文件,不需要编写实现类。

开发规范:

  1. Mapper接口的类路径xxxMapper.xml文件中的namespace相同
  2. Mapper接口方法名称xxxMapper.xml中定义的每个statementid相同
  3. Mapper接口方法的输入参数类型xxxMapper.xml中定义的每个sql的parameterType的类型相同
  4. Mapper接口方法的返回值类型xxxMapper.xml中定义的每个sql的resultType类型相同

pom.xml

4.0.0
com.cyb
mybatis
war
0.0.1-SNAPSHOT
mybatis Maven Webapp
http://maven.apache.org
org.mybatis
mybatis
3.4.6
mysql
mysql-connector-java
8.0.20
junit
junit
4.12
mybatis

SqlMapConfig.xml

db.properties

db.driver=com.mysql.jdbc.Driverdb.url=jdbc:mysql://127.0.0.1:3306/cybdb.username=rootdb.password=root

UserMapper.xml

Use.java

package com.cyb.mybatis.demo;import java.util.Date;public class User {    private int id;    private String username;    private Date birthday;    private int sex;    private String address;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public int getSex() {        return sex;    }    public void setSex(int sex) {        this.sex = sex;    }    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }    @Override    public String toString() {        return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address="                + address + "]";    }}

UserMapper.java

package com.cyb.mybatis.mapper;import com.cyb.mybatis.demo.User;public interface UserMapper {    /**     * 根据用户id查询用户信息     * @param id 内码     * @return     * @throws Exception     */    public User queryUserById(int id) throws Exception;}

MybatisDemo.java

package com.cyb.mybatis.demo;import java.io.InputStream;import java.util.Date;import java.util.List;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Before;import org.junit.Test;import com.cyb.mybatis.mapper.UserMapper;public class MybatisDemo {    private SqlSessionFactory sqlSessionFactory;    @Before    public void init() throws Exception {        // 指定全局配置文件路径        String resource = "SqlMapConfig.xml";        // 加载资源文件(包括全局文件和映射文件)        InputStream inputStream = Resources.getResourceAsStream(resource);        // 使用构建者模式创建SqlSessionFactory        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);    }    @Test    public void testSelect() throws Exception {        // 由SqlSessionFactory工厂去创建SqlSession(会话)        SqlSession sqlSession = sqlSessionFactory.openSession();        // 调用SqlSession接口,去实现数据库的CRUD        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);            User user = userMapper.queryUserById(1);        System.out.println(user);        // 释放资源        sqlSession.close();    }}

项目结构

 

测试 

全局配置文件

properties标签

  可以引入java属性文件中的配置信息

typeAlias标签

  别名的作用:为了简化映射文件中parameterType和resultType中POJO类型的包名

默认支持别名

批量指定别名(推荐)

注:可以写多个package,但是package和typeAlias不能一起用!!!

单个指定别名(typeAlias)

注:可以写多个typeAlias,但是package和typeAlias不能一起用!!!

mappers标签

<mapper resource="" /> (不推荐)

 

注:一次加载一个映射文件,相当于资源路径

<package name="" />(推荐

  注册指定包下的所有mapper接口,来加载mapper映射文件。

注:mapper接口和mapper映射文件名称相同,且放到同一目录下

关联查询

一对多

Collection标签:定义了一对多关联的结果映射。property="orders":关联查询的结果集存储在User对象的上哪个属性。ofType="orders":指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。

源码部分

构建SqlSessionFactory过程

  下面我们具体的查看下是如何构建SqlSessionFactory对象

  通过源码可以看出,最终生成一个DefaultSqlSessionFactory实例,这个不是我们关注的重点,我们核心是关注如何初始化对象的。

构建XMLConfigBuilder对象

  build函数首先会构造一个XMLConfigBuilder对象,他是解析XML配置文件的。

 

  • XMLxxxBuilder:解析XML配置文件的,不同类型的XMLxxxBuilder解析不同的部位
    • XMLConfigBuilder:解析mybatis全局配置文件
    • XMLMapperBuilder:解析mybatis映射文件
    • XMLStatementBuilder:解析映射文件中statement语句(CRUD Sql语句)
    • MapperBuilderAssistant:辅助解析映射文件并生成MappedStatement对象

这些XMLxxxBuilder都有一个共同的父类->BaseBuilder这个父类维护了全局的Configuration对象,mybatis的配置文件解析后就以Configuration对象的形式存储。   

 

加载映射文件

  底层代码量较多,录制的gif图片较大不能上传,分3段上传的,内容都是连续的;这里抛块砖,实际还是要自己打个断点,跟踪下底层源码,根据自身爱好,研究相应内容,准备工作:了解知识点:XPath(如,解析XML配置文件,)、设计模式(如:构建者模式,)、面向对象等等,要不然跟踪源码是件很痛苦的事儿~~~

构建者模式使用地方

XPath使用地方

补充

注意:此处用到了遍历list节点,因为映射文件有很多的select、update、delete标签哦~

打开session会话

  我们可以看到,SqlSessionFactory是一个接口,里面有很多重载方法

SqlSessionFactory接口重载说明

 

跟踪到SqlSessionFactory的实现类DefaultSqlSessionFactory

  通过跟踪到DefaultSqlSessionFactory,我们可以看到,底层使用了重载,默认自动提交事务未false,从而解答了,我们使用默认无参构造函数时,对数据库进行:插入、修改、删除,需要手动提交事务

  细心的小伙伴此时会问,问什么跟踪源码的时候,他不是有两个实现类吗,为什么要跟踪上面一个,不跟踪下面那个,是因为创建SqlSessionFactory的时候,默认返回的是DefaultSqlSessionFactory

跟踪selectOne

selectList分析

 

我们跟踪下,是如何从Configuration全局配置文件中(从Map中获取),获取MapperStatement的;注:这个全局配置文件(configuration)是在初始化SqlSessionFactory时加载的

接下来我们跟踪下,是如何解析传递的参数的,分3种处理情况,分别为:集合、list、其他;注:参数类型与xxxMapper.xml的parameterType类型想对应,传什么类型,走什么情况

 

跟踪executor.query

  先走下面那个实现类,在走上面那个实现类

 

为什么先走下面那个实现类呢?看gif,先委托下面那个实现类

设置参数绑定

  打个断点,调试下就知道了!!

转载地址:http://qdmkz.baihongyu.com/

你可能感兴趣的文章
C#之反射、元数据详解
查看>>
通俗易懂设计模式解析——单例模式
查看>>
通俗易懂设计模式解析——抽象工厂模式
查看>>
.NET日志记录之——log4net划重点篇
查看>>
SSM商城项目(十二)
查看>>
Redis必知必会系列
查看>>
第5章选择结构程序设计
查看>>
第4章 最简单的C程序设计——顺序程序设计
查看>>
C#ADO.NET操作数据代码汇总
查看>>
原创企业级控件库之组合查询控件
查看>>
信息系统项目管理系列之七:项目时间管理
查看>>
RDIFramework.NET ━ 9.2 员工管理 ━ Web部分
查看>>
ANDROID : NEW IDEA
查看>>
第1章 什么是JavaScript
查看>>
前端数据渲染及mustache模板引擎的简单实现
查看>>
控制台基于Quartz.Net组件实现定时任务调度(一)
查看>>
Asp.Net Core之Identity应用(下篇)
查看>>
谈谈对IOC及DI的理解与思考
查看>>
【Dubbo】Zookeeper+Dubbo项目demo搭建
查看>>
CSS3中字体平滑处理和抗锯齿渲染
查看>>