扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
今天就跟大家聊聊有关Mybatis框架的作用有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
梁园ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:13518219792(备注:SSL证书合作)期待与您的合作!mybatis基本架构
mybatis的源码应该算是比较容易阅读的,首先mybatis核心功能就是执行Sql语句,但在其基础上又有许多增强的地方(动态Sql,ORM等)。看一个框架的时候,第一步是对整个框架有一个大体的了解。例如mybatis,我们可以从初始化到完成一个sql请求为主线,看一下涉及了哪些类。我个人总结了一下,mybatis的框架主要的核心类有4个
Configuration
Configuration就是用于解析、保存、处理Mybatis的配置内容,包括了
mybatis基本配置,例如支持数据库中的字段支持下标转驼峰mapUnderscoreToCamelCase=true等等,参看Mybatis配置说明
SqlMapper管理,也就是通过xml或者注解写的一些sql映射。相关的类可以查看源码中MappedStatement类。
创建类,Configuration还有一些创建类的功能,例如Executor、StatementHandler。这个2个类后面还会说到
小节Configuration
总结Configuration的功能,当然,如何读取和解析相关文件是Configuration中大部分代码做的事。这些都是为了准备后面mybatis运行的基本条件。Configuration中创建类是因为创建的这些类都依赖于Configuration(但这样做数据和逻辑没有做到分离)。
SqlSession
SqlSession可能是mybatis中我们最常用的类,其实他是一个门面类,直接对外提供服务
public interface SqlSession extends Closeable {T selectOne(String statement); List selectList(String statement, Object parameter); int delete(String statement); void rollback(); void commit(); ... }
这些方法都是直接提供给外部调用的。看到这些方法是不是很亲切。(我个人在看源码的时候看到一些自己用过的一些类或方法的时候都有种莫名的亲近感。感觉终于和我的认知世界有交集了)
SqlSession的创建
SqlSessionFactor是用于创建SqlSession建造者,提供给外部快速创建一个SqlSession。是一个工厂类,而SqlSessionFactor的创建则是由SqlSessionFactorBuilder。
Executor
前面说了SqlSession只是一个门面类,Executor才是负责Sql语句执行的。因此Executor才是整个mybatis核心。Executor的实现类有
BaseExecutor:看名字知道是最基础Executor,其他的Executor都和这个类有一定的关系
CachingExecutor:每次查询的时候会先从缓存中获取,每次有增删改的时候会让缓存失效。CachingExecutor其实是一个代理内,内部代理了BaseExecutor(或其子类)。在BaseExecutor基础上增加了缓存操作。
相关类
我们看一个Executor参数最多的一个方法
List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
这些类都对执行Sql有一定关系
MappedStatement
具体点来理解就是我们定义的Sql映射语句,例如我们xml定义的:
paramter
这个就是传递给sql映射的参数,用于生成和填充动态sql语句
RowBound
限定一次查询数据量,类很简单,看代码就明白,不多说
public class RowBounds { public static final int NO_ROW_OFFSET = 0; public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; public static final RowBounds DEFAULT = new RowBounds(); private int offset; private int limit; public RowBounds() { this.offset = NO_ROW_OFFSET; this.limit = NO_ROW_LIMIT; } public RowBounds(int offset, int limit) { this.offset = offset; this.limit = limit; } }
ResultHandler
这个和本地缓存有关,用于保存一个查询语句的缓存对象,下次有相同的查询语句的时候就会先尝试从本地缓存中获取。 注意:
,mybatis有2级缓存,第一级是CachingExecutor,第二级缓存就是mybatis的本地缓存,也就是和ResultHandler
缓存失效策略是和一级缓存一样,任何增删改都会清空本地缓存
CacheKey
一个查询语句的在本地缓存中的key,根据sql语句,参数等等组成
BoundSql
这个对象就是本次实际需要执行的sql语句有关的信息,
public class BoundSql { private String sql; private ListparameterMappings; private Object parameterObject; private Map additionalParameters; private MetaObject metaParameters; ...
如果说parameter参数是实际传入的参数,那么BoundSql就是根据传入参数进行相关解析后的结果。他的创建在MappedStatement中,根据parameter和当前执行MappedStatement生成
public BoundSql getBoundSql(Object parameterObject) { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); ListparameterMappings = boundSql.getParameterMappings(); if (parameterMappings == null || parameterMappings.isEmpty()) { boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); } // check for nested result maps in parameter mappings (issue #30) for (ParameterMapping pm : boundSql.getParameterMappings()) { String rmId = pm.getResultMapId(); if (rmId != null) { ResultMap rm = configuration.getResultMap(rmId); if (rm != null) { hasNestedResultMaps |= rm.hasNestedResultMaps(); } } } return boundSql; }
Interceptor
Mybatis提供了Interceptor用于在执行Executor之前进行一些操作,mybatis是怎么使用Interceptor。其实就是在创建Executor时候,会
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } //看这里!!! executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
这里主要是通过jdk动态代理实现的
public class Plugin implements InvocationHandler { ... public static Object wrap(Object target, Interceptor interceptor) { Map, Set > signatureMap = getSignatureMap(interceptor); Class> type = target.getClass(); Class>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; } ... @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Set methods = signatureMap.get(method.getDeclaringClass()); if (methods != null && methods.contains(method)) { return interceptor.intercept(new Invocation(target, method, args)); } return method.invoke(target, args); } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } }
这样在调用Executor的时候就会先判断是否满足Interceptor的执行条件,满足则会先执行Intercepter#intercept()方法
最底层的Handler
要说直接和Jdbc打交道的就是各种Handler类,例如
StatementHandler: 处理java.sql.Statement
ParameterHandler: 向PreparedStatement中设置参数
ResultSetHandler:处理sql执行结果,并转换成指定的类对象 上面的这些其实都不复杂,所以代码还是比较好理解的
Transaction
每个Executor生成的时候都会把Transaction传入,在BaseExecutor中Transaction是其成员变量,那Transaction的作用是什么呢?
public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; Integer getTimeout() throws SQLException; }
其实之前一直都没提到过Connect谁来管理,这里可以看出来,Transaction负责了Connection的获取,以及对这次Connect的提交和回滚等操作。这个类也是比较好理解的。Executor的commit或者rollback最后都是调用Transaction的
看完上述内容,你们对Mybatis框架的作用有哪些有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流