态度决定一切。
一、容器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
的解析
最终会调用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动态代理技术,在内存中帮我们创建一个代理类出来。(虽然你看不到,但他确实存在)