为什么建议框架源码学习从Mybatis开始(上)

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 为什么建议框架源码学习从Mybatis开始(上)

态度决定一切。

一、容器Configuration二、动态SQL模板1、MappedStatement(映射器)2、解析过程三、SqlSession1.基本介绍2.分类3.Executor四、Mapper(殊途同归)1.存在的意义2.工作原理五、缓存1.一级缓存2.二级缓存2.1基本信息2.2如何工作六、插件七、结果映射八、总结

看过Mybatis后,我觉得Mybatis虽然小,但是五脏俱全,而且设计精湛。

这个黑盒背后是怎样一个设计,下面讲讲我的理解


一、容器Configuration


Configuration 像是Mybatis的总管,Mybatis的所有配置信息都存放在这里,此外,它还提供了设置这些配置信息的方法。Configuration可以从配置文件里获取属性值,也可以通过程序直接设置。

用一句话概述Configuration,他类似Spring中的容器概念,而且是中央容器级别,存储的Mybatis运行所需要的大部分东西。


二、动态SQL模板


使用mybatis,我们大部分时间都在干嘛?在XML写SQL模板,或者在接口里写SQL模板

<?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:命名空间,命名空间唯一 -->
<mapper namespace="UserMapper">
   <select id="selectUser" resultType="com.wqd.model.User">
      select * from user where id= #{id}
   </select>
</mapper>

或者

@Mapper
public interface UserMapper {
    @Insert("insert into user( name, age) " +
            "values(#{user.name}, #{user.age})")
    void save(@Param("user") User user);
    @Select("select * from user where id=#{id}")
    User getById(@Param("id")String id);
}

这对于Mybatis框架内部意味着什么?


1、MappedStatement(映射器)

  • 就像使用Spring,我们写的Controller类对于Spring 框架来说是在定义BeanDefinition一样。
  • 当我们在XML配置,在接口里配置SQL模板,都是在定义Mybatis的域值MappedStatement

一个SQL模板对应MappedStatement

mybatis 在启动时,就是把你定义的SQL模板,解析为统一的MappedStatement对象,放入到容器Configuration中。每个MappedStatement对象有一个ID属性。这个id同我们平时mysql库里的id差不多意思,都是唯一定位一条SQL模板,这个id 的命名规则:命名空间+方法名

Spring的BeanDefinition,Mybatis的MappedStatement


2、解析过程

同Spring一样,我们可以在xml定义Bean,也可以java类里配置。涉及到两种加载方式。

这里简单提一下两种方法解析的入口:


1.xml方式的解析

提供了XMLConfigBuilder组件,解析XML文件,这个过程既是Configuration容器创建的过程,也是MappedStatement解析过程。

XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
Configuration config = parser.parse()


2.与Spring使用时

会注册一个MapperFactoryBean,在MapperFactoryBean在实例化,执行到afterPropertiesSet()时,触发MappedStatement的解析


image.png

image.png


最终会调用Mybatis提供的一MapperAnnotationBuilder 组件,从其名字也可以看出,这个是处理注解形式的MappedStatement

殊途同归形容这两种方式很形象,感兴趣的可以看看源码


三、SqlSession


1.基本介绍

有了SQL模板,传入参数,从数据库获取数据,这就是SqlSession干的工作。

SqlSession代表了我们通过Mybatis与数据库进行的一次会话。使用Mybatis,我们就是使用SqlSession与数据库交互的。

我们把SQL模板的id,即MappedStatement 的id 与 参数告诉SqlSession,SqlSession会根据模板id找到对应MappedStatement ,然后与数据交互,返回交互结果

User user = sqlSession.selectOne("com.wqd.dao.UserMapper.selectUser", 1);


2.分类

  • DefaultSqlSession:最基础的sqlsession实现,所有的执行最终都会落在这个DefaultSqlSession上,线程不安全
  • SqlSessionManager : 线程安全的Sqlsession,通过ThreadLocal实现线程安全。


3.Executor

Sqlsession有点像门面模式,SqlSession是一个门面接口,其内部工作是委托Executor完成的。

public class DefaultSqlSession implements SqlSession {
  private Configuration configuration;
  private Executor executor;//就是他
 }
复制代码

我们调用SqlSession的方法,都是由Executor完成的。

public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      ----交给Executor
      executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }


四、Mapper(殊途同归)


1.存在的意义

UserMapper userMapper = sqlsession.getMapper(UserMapper.class);
User user = userMapper.getById("51");

Mapper的意义在于,让使用者可以像调用方法一样执行SQL。

区别于,需要显示传入SQL模板的id,执行SQL的方式。

User user = sqlSession.selectOne("com.wqd.dao.UserMapper.getById", 1);


2.工作原理

代理!!!代理!!! 代理!!!Mapper通过代理机制,实现了这个过程。

1、MapperProxyFactory: 为我们的Mapper接口创建代理。

  • 单独使用Mybatis时,Mybatis会调用MapperRegistry.addMapper()方法,为UserDao接口,创建new MapperProxyFactory(type)
  • 当和Spring一起使用时,MapperScannerRegistrar组件触发ClassPathMapperScanner组件的doScan方法将UserDao的BeanDefinition 的BeanClass设置为MapperProxyFactory, 在走SpringBean实例化时,就从MapperProxyFactory里获取UserDao的实例对象(即代理对象)。


public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

MapperProxyFactory通过JDK动态代理技术,在内存中帮我们创建一个代理类出来。(虽然你看不到,但他确实存在)


相关文章
|
19天前
|
SQL Java 关系型数据库
Java中的ORM框架——myBatis
Java中的ORM框架——myBatis
|
4天前
|
Java 数据库连接 Spring
Spring 整合 MyBatis 底层源码解析
Spring 整合 MyBatis 底层源码解析
|
7天前
|
Java 关系型数据库 MySQL
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
15 4
|
7天前
|
SQL Java 数据库连接
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
16 2
|
9天前
|
SQL XML Java
【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)
【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)
11 1
|
17天前
|
Java 数据库连接 Android开发
SSM框架——使用MyBatis Generator自动创建代码
SSM框架——使用MyBatis Generator自动创建代码
18 2
|
2天前
|
SQL 缓存 Java
Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件
Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件
|
6天前
|
XML Java 数据库连接
浅谈后端boot框架整合第三方技术JUnit MyBatis Druid整体思想
浅谈后端boot框架整合第三方技术JUnit MyBatis Druid整体思想
8 0
|
10天前
|
Java 数据库连接 Maven
Mybatis学习
Mybatis学习
10 0
|
2月前
|
XML Java 数据库连接
利用MyBatis框架操作数据库2
利用MyBatis框架操作数据库
25 2