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