Mybatis3源码分析(6)简单手写思路及面试题

手写基本流程

流程

  1. 定义接口 Mapper 和方法,用来调用数据库操作。Mapper 接口操作数据库需要通过代理类。
  2. 定义配置类对象 Configuration。
  3. 定义应用层的 API SqlSession。它有一个 getMapper()方法,我们会从配置类Configuration 里面使用 Proxy.newProxyInatance()拿到一个代理对象MapperProxy。
  4. 有了代理对象 MapperProxy 之后,我们调用接口的任意方法,就是调用代理对象的 invoke()方法。
  5. 代理对象 MapperProxy 的 invoke()方法调用了 SqlSession 的 selectOne()。
  6. SqlSession 只是一个 API,还不是真正的 SQL 执行者,所以接下来会调用执行器 Executor 的 query()方法。
  7. 执行器 Executor 的 query()方法里面就是对 JDBC 底层的 Statement 的封装,最终实现对数据库的操作,和结果的返回。
    附上手写Mybatis github地址

ps:只是简单的理解加深印象,里面有很多不足。

面试分析

  1. resultType 和 resultMap 的区别?
resultType 是<select>标签的一个属性,适合简单对象(POJO、JDK 自带类型:Integer、String、Map 等)只能自动映射,适合单表简单查询。
resultMap 是一个可以被引用的标签,适合复杂对象,可指定映射关系,适合关联复合查询。
  1. 标签collection 和 标签association 的区别?
association:一对一
collection:一对多、多对多
  1. PrepareStatement 和 Statement 的区别?
两个都是接口,PrepareStatement 是继承自 Statement 的;
Statement 处理静态 SQL,PreparedStatement 主要用于执行带参数的语句;
PreparedStatement 的 addBatch()方法一次性发送多个查询给数据库;
PS 相似 SQL 只编译一次(对语句进行了缓存,相当于一个函数),减少编译次数;
PS 可以防止 SQL 注入;
MyBatis 默认值:PREPARED 也就是PreparedStatement
  1. MyBatis 解决了什么问题?
1) 资源管理(底层对象封装和支持数据源)
2)结果集自动映射
3)SQL 与代码分离,集中管理
4)参数映射和动态 SQL
5)其他:缓存、插件等
  1. MyBatis 编程式开发中的核心对象及其作用?
SqlSessionFactoryBuilder 创建工厂类
SqlSessionFactory 创建会话
SqlSession 提供操作接口
MapperProxy 代理 Mapper 接口后,用于找到 SQL 执行
  1. Java 类型和数据库类型怎么实现相互映射?
通过 TypeHandler,例如 Java 类型中的 String 要保存成 varchar,就会自动调用相应的 Handler。如果没有系统自带的 TypeHandler,也可以自定义--比如之前文章中写的json转对象的操作。
  1. SIMPLE/REUSE/BATCH 三种执行器的区别?
SimpleExecutor 使用后直接关闭 Statement:closeStatement(stmt);
ReuseExecutor 放在缓存中,可复用:PrepareStatement:getStatement();
BatchExecutor 支持复用且可以批量执行 update(),通过 ps.addBatch()实现handler.batch(stmt);
  1. MyBatis 一级缓存与二级缓存的区别?
一级缓存:在同一个会话(SqlSession)中共享,默认开启,维护在 BaseExecutor中。
二级缓存:在同一个 namespace 共享,需要在 Mapper.xml 中开启,维护在CachingExecutor 中。
  1. MyBaits 支持哪些数据源类型?
UNPOOLED:不带连接池的数据源。
POOLED : 带 连 接 池 的 数 据 源 , 在 PooledDataSource 中 维 护PooledConnection。
JNDI:使用容器的数据源,比如 Tomcat 配置了 C3P0。
自定义数据源:实现 DataSourceFactory 接口,返回一个 DataSource。当 MyBatis 集成到 Spring 中的时候,使用 Spring 的数据源
  1. 关联查询的延迟加载是怎么实现的?
动态代理(JAVASSIST、CGLIB),在创建实体类对象时进行代理,在调用代理对象的相关方法时触发二次查询。
  1. MyBatis 翻页的几种方式和区别?
逻辑翻页:通过 RowBounds 对象。
物理翻页:通过改写 SQL 语句,可用插件拦截 Executor 实现。
  1. 解析全局配置文件的时候,做了什么?
创建 Configuration,设置 Configuration
解析 Mapper.xml,设置 MappedStatement
  1. 没有实现类,MyBatis 的方法是怎么执行的?
MapperProxy 代理,代理类的 invoke()方法中调用了 SqlSession.selectOne()
  1. 接口方法和映射器的 statement id 是怎么绑定起来的?(怎么根据接口方法拿到 SQL 语句的?)
MappedStatement 对象中存储了 statement 和 SQL 的映射关系
  1. 四大对象是什么时候创建的?
Executor:openSession()
StatementHandler、ResultsetHandler、ParameterHandler:
执行 SQL 时,在 SimpleExecutor 的 doQuery()中创建
  1. MyBatis 哪些地方用到了代理模式?
接口查找 SQL:MapperProxy
日志输出:ConnectionLogger、StatementLogger
连接池:PooledDataSource 管理的 PooledConnection
延迟加载:ProxyFactory(JAVASSIST、CGLIB)
插件:Plugin
Spring 集成:SqlSessionTemplate 的内部类 SqlSessionInterceptor
  1. MyBatis 插件怎么编写和使用?原理是什么?
使用:继承 Interceptor 接口,加上注解,在 mybatis-config.xml 中配置
原理:动态代理,责任链模式,使用 Plugin 创建代理对象
在被拦截对象的方法调用的时候,先走到 Plugin 的 invoke()方法,再走到Interceptor 实现类的 intercept()方法,
最后通过 Invocation.proceed()方法调用被拦截对象的原方法
  1. JDK 动态代理,代理能不能被代理?
能。层层代理先进后出
  1. MyBatis 集成到 Spring 的原理是什么?
SqlSessionTemplate 中有内部类SqlSessionInterceptor对DefaultSqlSession进行代理;
MapperFactoryBean 继 承 了 SqlSessionDaoSupport 获 取SqlSessionTemplate;
接口注册到 IOC 容器中的 beanClass 是 MapperFactoryBean。
  1. DefaulSqlSession 和 SqlSessionTemplate 的区别是什么?
一个线程安全一个线程不安全
1)为什么 SqlSessionTemplate 是线程安全的?
其内部类 SqlSessionInterceptor 的 invoke()方法中的 getSqlSession()方法:如果当前线程已经有存在的 
SqlSession 对象,会在 ThreadLocal 的容器中拿到SqlSessionHolder,获取 DefaultSqlSession。
如果没有,则会 new 一个 SqlSession,并且绑定到 SqlSessionHolder,放到ThreadLocal 中。SqlSessionTemplate 
中在同一个事务中使用同一个 SqlSession。调用 closeSqlSession()关闭会话时,如果存在事务,减少 holder 的引用计数。否则直接关闭 SqlSession。
2) 在编程式的开发中,有什么方法保证 SqlSession 的线程安全?
SqlSessionManager 同时实现了 SqlSessionFactory、SqlSession 接口,通过ThreadLocal 容器维护 SqlSession。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章