mybatis源码解析
2024-09-09 14:00:25 0 举报
AI智能生成
1、springbean创键 2、refresh全流程 3、springaop 4、spring transactional 5、spring常用注解 6、持续更新...
作者其他创作
大纲/内容
XMLConfigBuilder.mappersElement mapper.xml 解析过程
1、获取 <package> 节点中的 name 属性
2、获取 resource/url/class 等属性
3、mapperParser.parse() 解析映射文件
1、configurationElement(parser.evalNode("/mapper")); 解析mapper节点
cacheElement 解析 <cache> 节点
1、获取type属性,如果type没有指定就用默认的PERPETUAL(早已经注册过的别名的PerpetualCache)
2、根据type从早已经注册的别名中获取对应的Class,PERPETUAL对应的Class是PerpetualCache.class
3、获取淘汰方式,默认为LRU(早已经注册过的别名的LruCache),最近最少使用到的先淘汰
4、builderAssistant.useNewCache 构建缓存对象 使用建造者设计模式
newCacheDecoratorInstance 使用装设器设计模式
resultMapElements 解析resultMap节点
XMLMapperBuilder.resultMapElement
1、获取 id 和 type 属性
2、获取 extends 和 autoMapping
3、resolveClass 获取type属性对应的类型
4、获取并遍历 <resultMap> 的子节点列表
5、buildResultMappingFromContext 解析 id 和 result 节点
processNestedResultMappings 递归调用resultMapElement解析<association> 和 <collection>的嵌套节点
MapperBuilderAssistant.buildResultMapping
ResultMap 对象
1、将 colum 转换成大写,并添加到 mappedColumns 集合中
2、添加属性 property 到 mappedProperties 集合中
3、添加 resultMapping 到 propertyResultMappings 中
4、添加 resultMapping 到 idResultMappings 中
sqlElement 解析sql节点
- buildStatementFromContext(context.evalNodes("select|insert|update|delete")); 解析select|insert|update|delete节点
XMLStatementBuilder.parseStatementNode
BaseBuilder.resolveClass 通过别名解析 resultType、parameterType对应的类型
XMLIncludeTransformer 解析 <include> 节点
1、将 <select>节点中的 <include> 节点替换为 <sql> 节点
2、PropertyParser.parse 将 source 节点属性中的占位符 ${} 替换成具体的属性值
3、将文本(text)节点中的属性占位符 ${} 替换成具体的属性值
langDriver.createSqlSource 解析 SQL 语句
new XMLScriptBuilder
XMLScriptBuilder.parseScriptNode
1、parseDynamicTags 解析 SQL 语句节点
1、如果节点是TEXT_NODE类型,若文本中包含 ${} 占位符,会被认为是动态节点
2、child 节点是 ELEMENT_NODE 类型,比如 <if>、<where> 等
3、NodeHandler.handleNode
2、new DynamicSqlSource
3、new RawSqlSource
builderAssistant.addMappedStatement
1、applyCurrentNamespace 拼接上命名空间
2、getStatementParameterMap 获取或创建 ParameterMap
3、configuration.addMappedStatement 添加 MappedStatement 到 configuration 的 mappedStatements 集合中
4、getStatementResultMaps 获取resultMa
2、configuration.addLoadedResource(resource) 添加资源路径到“已解析资源集合”中
3、bindMapperForNamespace(); 通过命名空间绑定 Mapper 接口
1、获取映射文件的命名空间
2、检测当前 mapper 类是否被绑定过
3、绑定 mapper 类
1、将 class和 MapperProxyFactory 进行绑定,MapperProxyFactory 可为 mapper 接口生成代理类
2、MapperAnnotationBuilder.parse 解析注解中的信息,支持注解
org.apache.ibatis.annotations
4、parsePendingResultMaps
5、parsePendingCacheRefs
6、parsePendingStatements
4、configuration.addMapper 解析注解
MapperRegistry.addMapper
MapperAnnotationBuilder.parse
解析的注解如下
mybatis SqlSession创建过程。使用了外观设计模式,隐藏底层的复杂性
sqlSessionFactory.openSession() 使用工厂设计模式
DefaultSqlSessionFactory.openSessionFromDataSource
1、configuration.getEnvironment() 获取配置中的环境信息,包括了数据源信息、事务等
2、getTransactionFactoryFromEnvironment(environment) 创建事务工厂,使用工厂设计模式
3、transactionFactory.newTransaction 创建事务,配置事务属性
4、configuration.newExecutor 创建执行器
根据不同的type,生成不同Executor。
new CachingExecutor CachingExecutor使用装饰器设计模式,将executor的功能添加上了二级缓存的功能
interceptorChain.pluginAll 此处调用插件,通过插件可以改变Executor行为
5、创建DefaultSqlSession对象返回
Select 语句执行过程分析
sqlSession.selectOne
configuration.getMappedStatement 通过MappedStatement的Id获取 MappedStatement
BaseExecutor.query 调用 Executor 实现类中的 query 方法
1、ms.getBoundSql 获取 BoundSql
BoundSql
SqlSource.getBoundSql(parameterObject)
1、创建 DynamicContext
2、rootSqlNode.apply 解析 SQL 片段,解析<if><where>等SqlNode
TextSqlNode.apply
createParser 创建 ${} 占位符解析器
GenericTokenParser.parse 解析 ${} 占位符,通过ONGL 从用户传入的参数中获取结果,替换text中的${} 占位符
3、SqlSourceBuilder.parse 将 sql 语句中的占位符 #{} 替换为问号 ?
1、创建 #{} 占位符处理器
2、new GenericTokenParser("#{", "}", handler) 创建 #{} 占位符解析器
3、GenericTokenParser.parse 解析 #{} 占位符,并返回解析结果字符串
处理不同的解析方式
子主题
4、装解析结果到 StaticSqlSource 中,并返回,因为所有的动态参数都已经解析了,可以封装成一个静态的SqlSource
4、sqlSource.getBoundSql 调用 StaticSqlSource 的 getBoundSql 获取 BoundSql
5、将 DynamicContext 的 ContextMap 中的内容拷贝到 BoundSql 中
2、createCacheKey 创建 CacheKey
3、query
1、localCache.getObject 从一级缓存中获取缓存项
2、queryFromDatabase 一级缓存未命中,则从数据库中查询
1、向缓存中存储一个占位符
2、doQuery 调用 doQuery 进行查询,这里使用了模板方法设计模式
SimpleExecutor.doQuery
1、configuration.newStatementHandler 创建 StatementHandler
new RoutingStatementHandler 创建路由handler
interceptorChain.pluginAll 使用插件
2、prepareStatement 创建 Statement
1、getConnection 获取数据库链接
1、transaction.getConnection() 通过transaction来获取Connection
JdbcTransaction
2、handler.prepare 创建 Statement
3、handler.parameterize 为 Statement 设置参数
3、handler.<E>query 执行查询操作
1、Statement.excute 执行数据库SQL
2、DefaultResultSetHandler.handleResultSets 进行resultSet自动映射
3、移除占位符
4、localCache.putObject 缓存查询结果
ResultSet 结果集自动映射成实体对象
ResultSetHandler.handleResultSets 进行resultSet自动映射
1、getFirstResultSet 获取第一个ResultSetWrapper,通常只会有一个。使用装饰器设计模式
2、mappedStatement.getResultMaps 从配置中读取对应的ResultMap,通常也只会有一个
3、handleResultSet 处理结果集
1、new DefaultResultHandler 创建默认的结果处理器
2、handleRowValues 处理结果集的行数据
1、handleRowValuesForNestedResultMap 处理嵌套映射
2、handleRowValuesForSimpleResultMap 处理简单映射
1、skipRows 根据 RowBounds 定位到指定行记录
2、每条数据遍历处理
3、getRowValue 从 resultSet 中获取结果
1、createResultObject 创建实体类对象
1、createResultObject 重载方法
1、createPrimitiveResultObject 如果有typeHandler
TypeHandler.getResult 根据typeHandler创建实体
BaseTypeHandler.getNullableResult
2、createParameterizedResultObject 如果constructorMappings不为空
根据构造参数创建实例
2、objectFactory.create(resultType) 通过 ObjectFactory 调用目标类的默认构造方法创建实例
constructor.newInstance() 通过反射,构造器实例化对象
4、createByConstructorSignature
2、ProxyFactory.createProxy 如果开启了延迟加载,则为 resultObject 生成代理类
2、applyAutomaticMappings 自动映射
1、createAutomaticMappings 获取 UnMappedColumnAutoMapping 列表
1、autoMappingsCache.get 从缓存中获取
2、ResultSetWrapper.getUnmappedColumnNames 缓存未命中,从 ResultSetWrapper 中获取未配置在 <resultMap> 中的列名
loadMappedAndUnmappedColumnNames 加载已映射与未映射列名
获取 <resultMap> 中配置的所有列名,并加入缓存
unMappedColumnNamesMap.get 获取未映射列名
3、metaObject.findProperty 将下划线形式的列名转成驼峰式,比如 AUTHOR_NAME -> authorName
4、检测当前属性是否存在于 resultMap 中
5、 metaObject.getSetterType 获取属性对应的类型
6、autoMapping.add 封装上面获取到的信息到 UnMappedColumnAutoMapping 对象中
7、autoMappingsCache.put 写入缓存
2、typeHandler.getResult 通过 TypeHandler 从结果集中获取指定列的数据
3、metaObject.setValue 通过元信息对象设置 value 到实体类对象的指定字段上
3、applyPropertyMappings 根据 <resultMap> 节点中配置的映射关系进行映射
1、ResultSetWrapper.getMappedColumnNames 获取已映射的列名
2、获取 ResultMapping集合
3、所有的ResultMapping遍历进行映射
4、getPropertyMappingValue 从结果集中获取指定列的数据
getNestedQueryMappingValue 获取关联查询的结果
1、propertyMapping.getNestedQueryId 获取关联查询 id,id = 命名空间 + <association> 的 select 属性值
2、configuration.getMappedStatement(nestedQueryId) 根据 nestedQueryId 获取关联的 MappedStatement
3、根据 nestedQueryId 获取关联的 MappedStatement 生成关联查询语句参数对象,参数类型可能是一些包装类,Map 或是自定义的实体类
4、nestedQuery.getBoundSql 获取 BoundSql,这里设置了运行时参数
5、new ResultLoader 创建结果加载器
6、检测当前属性是否需要延迟加载,是:添加延迟加载相关的对象到 loaderMap 集合中
7、resultLoader.loadResult否:直接执行关联查询
typeHandler.getResult 从 ResultSet 中获取指定列的值
5、若获取到的值为 DEFERED,则延迟加载该值
6、metaObject.setValue 将获取到的值设置到实体类对象中
4、storeObject 存储结果到resultHandler的ResultList,最后ResultList加入multipleResults中返回
3、将结果加入multipleResults中
Spring-MyBatis框架使用和源码解析
SqlSessionFactoryBean
spring doCreateBean 详见spring源码解析
populateBean方法已经将SqlSessionFactoryBean对象的属性进行赋值了
initializeBean
afterPropertiesSet
buildSqlSessionFactory
xmlConfigBuilder.getConfiguration()
xmlConfigBuilder.parse() 解析mybatis-Config.xml文件
new SpringManagedTransactionFactory() 事务默认采用SpringManagedTransaction
configuration.setEnvironment 为sqlSessionFactory绑定事务管理器和数据源
new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments())
configuration, mapperLocation.toString(), configuration.getSqlFragments())
this.sqlSessionFactoryBuilder.build 调用sqlSessionFactoryBuilder创建sqlSessionFactory对象实例
Mybatis事务如何被spring管理
SpringManagedTransactionFactory
SpringManagedTransaction
openConnection
DataSourceUtils.getConnection 通过DataSourceUtils获取connection
doGetConnection 这里从ThreadLocal中获取ConnectionHolder
fetchConnection 如果没有使用@Transaction,那调用Mapper接口方法时,也是通过Spring的方法获取Connection
TransactionSynchronizationManager.bindResource 将获取到的ConnectionHolder放入ThreadLocal中
BaseBuilder
Configuration 对应于mybatis的全局配置文件mybatis-config.xml的配置
parse
TypeAliasRegistry 注册了很多别名
TypeHandlerRegistry
SqlSessionFactoryBuilder
XMLConfigBuilder.parse
parseConfiguration 解析配置文件
1、propertiesElement 解析properties属性
1、context.getChildrenAsProperties() 解析 propertis 的子节点,并将这些节点内容转换为属性对象 Properties
2、获取 propertis 节点中的 resource 和 url 属性值
3、加载并解析属性文件
4、configuration.setVariables(defaults) 将属性值设置到 configuration 中
Mapper底层原理,为什么不用写实现类就能访问数据库
DefaultSqlSession.getMapper
1、从 knownMappers 中获取与 type 对应的 MapperProxyFactory
2、创建代理对象
MapperProxyFactory
newInstance 创建MapperProxy代理对象,使用代理设计模式
MapperProxy.invoke
1、如果方法是定义在 Object 类中的,则直接调用
2、cachedInvoker 缓存中获取MapperMethod
3、执行
MapperMethod
SqlCommand 包含SQL相关信息,比如MappedStatement的id属性,(mapper.EmployeeMapper.getAll)
MethodSignature 包含了关于执行的Mapper方法的参数类型和返回类型。
1、TypeParameterResolver.resolveReturnType 通过反射解析方法返回类型
2、检测返回值类型是否是 void、集合或数组、Cursor、Map 等
3、解析 @MapKey 注解,获取注解内容
4、获取 RowBounds 参数在参数列表中的位置,如果参数列表中
5、获取 ResultHandler 参数在参数列表中的位置
6、new ParamNameResolver 解析参数列表
execute 执行sql
1、根据 SQL 类型执行相应的数据库操作
2、convertArgsToSqlCommandParam 传入参数转换
PooledDataSource 数据库连接池
PoolState 连接池配置
Mybatis 一级缓存和二级缓存源码
一级缓存
openSession
openSessionFromDataSource
this.configuration.newExecutor 创建sql执行器
SimpleExecutor 默认创建
PerpetualCache 一级缓存数据存储
query
getBoundSql
BaseExecutor.createCacheKey 创建CacheKey
BaseExecutor.query
localCache.getObject 先从缓存中获取
queryFromDatabase 缓存中没有查询数据库
doQuery 执行sql
localCache.putObject(key, list) 将结果放入缓存
update
clearLocalCache insert|delete|update,清除缓存
doUpdate
当关闭SqlSession时,也会清除SqlSession中的一级缓存
二级缓存
CachingExecutor 二级缓存
二级缓存的生效必须在session提交或关闭之后才会生效
query
ms.getBoundSql
createCacheKey 创建CacheKey
query
ms.getCache() 获取二级缓存
flushCacheIfRequired 如果有必要刷新缓存
tcm.getObject(cache, key) 二级缓存中获取数据
delegate.<E>query 二级缓存没有获取到结果,执行查询,并保存一级缓存
tcm.putObject(cache, key, list); 缓存查询结果
CacheKey
使用redis,存储二级缓存
通过自定义实现cache接口,redis缓存存储
整合springboot实现redis缓存
@MapperScan 将Mapper接口生成代理注入Spring容器
MapperScannerRegistrar
registerBeanDefinitions
1、AnnotationAttributes.fromMap 获取MapperScan 注解,如@MapperScan("com.chenhao.mapper")
2、BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class) 创建扫描器
3、builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef")) 设置SqlSessionFactory的名称
5、annoAttrs.getStringArray 获取配置的包路径,如com.lxy.mapper
6、registry.registerBeanDefinition(beanName, builder.getBeanDefinition()) 注册Bean实例
SqlSessionTemplate 使用静态代理设计模式
0 条评论
下一页