mybatis设计与原理
2021-02-02 16:57:56 1 举报
AI智能生成
csdn专栏学习整理,感谢作者亦山 https://blog.csdn.net/luanlouis
作者其他创作
大纲/内容
关键点
初始化机制
配置初始化
MyBatis初始化的过程,就是创建 Configuration对象的过程
初始化方式
基于XML配置文件:基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中,
MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
基于Java API:这种方式不使用XML配置文件,需要MyBatis使用者在Java代码中,
手动创建Configuration对象,然后将配置参数set 进入Configuration对象中
手动创建Configuration对象,然后将配置参数set 进入Configuration对象中
mybatis初始化流程
数据源和连接池
Mybatis数据源DataSource分类
UNPOOLED 不使用连接池的数据源
POOLED 使用连接池的数据源
JNDI 使用JNDI实现的数据源
DataSource UML图
数据源DataSource的创建过程
1.MyBatis在初始化时,解析此文件,根据<dataSource>的type属性来创建相应类型的的数据源DataSource
2. MyBatis是通过工厂模式来创建数据源DataSource对象的,MyBatis定义了抽象的工厂接口:org.apache.ibatis.datasource.DataSourceFactory,通过其getDataSource()方法返回数据源DataSource
3.MyBatis创建了DataSource实例后,会将其放到Configuration对象内的Environment对象中, 供以后使用
DataSouceFactoryUML图
DataSource什么时候创建Connection对象
当我们需要创建SqlSession对象并需要执行SQL语句时,这时候MyBatis才会去调用dataSource对象来创建java.sql.Connection对象
不使用连接池的UnpooledDataSource
UnpooledDataSouce时序图
为什么要使用连接池
创建一个java.sql.Connection对象的代价是如此巨大,是因为创建一个Connection对象的过程,
在底层就相当于和数据库建立的通信连接,在建立通信连接的过程,消耗了这么多的时间,
而往往我们建立连接后(即创建Connection对象后),就执行一个简单的SQL语句,然后就要抛弃掉,这是一个非常大的资源浪费
在底层就相当于和数据库建立的通信连接,在建立通信连接的过程,消耗了这么多的时间,
而往往我们建立连接后(即创建Connection对象后),就执行一个简单的SQL语句,然后就要抛弃掉,这是一个非常大的资源浪费
解决方案
对于需要频繁地跟数据库交互的应用程序,可以在创建了Connection对象,并操作完数据库后,可以不释放掉资源,而是将它放到内存中,
当下次需要操作数据库时,可以直接从内存中取出Connection对象,不需要再创建了,这样就极大地节省了创建Connection对象的资源消耗
当下次需要操作数据库时,可以直接从内存中取出Connection对象,不需要再创建了,这样就极大地节省了创建Connection对象的资源消耗
PooledDataSource连接池
PoolState 连接池
连接池中获取connection
Connection对象的回收
使用池化思想,怎样实现Connection对象调用了close()方法,而实际是将其添加到连接池中
要使用代理模式
为真正的Connection对象创建一个代理对象,代理对象所有的方法都是调用相应的真正Connection对象的方法实现。
当代理对象执行close()方法时,要特殊处理,不调用真正Connection对象的close()方法,而是将Connection对象添加到连接池中。
为真正的Connection对象创建一个代理对象,代理对象所有的方法都是调用相应的真正Connection对象的方法实现。
当代理对象执行close()方法时,要特殊处理,不调用真正Connection对象的close()方法,而是将Connection对象添加到连接池中。
MyBatis的PooledDataSource的PoolState内部维护的对象是PooledConnection类型的对象,
而PooledConnection则是对真正的数据库连接java.sql.Connection实例对象的包裹器。
而PooledConnection则是对真正的数据库连接java.sql.Connection实例对象的包裹器。
事务管理
概述
数据库事务:创建(create)、提交(commit)、回滚(rollback)、关闭(close)
MyBatis将事务抽象成了Transaction接口
MyBatis的事务管理形式
一、使用JDBC的事务管理机制:即利用java.sql.Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等
二、使用MANAGED的事务管理机制:这种机制MyBatis自身不会去实现事务管理,
而是让程序的容器如(JBOSS,Weblogic)来实现对事务的管理
而是让程序的容器如(JBOSS,Weblogic)来实现对事务的管理
事务的配置、创建和使用
事务的配置
事务工厂TransactionFactory
事务工厂的创建
事务工厂Transaction定义了创建Transaction的两个方法:
与JDBC 和MANAGED两种Transaction相对应
与JDBC 和MANAGED两种Transaction相对应
通过指定的Connection对象创建Transaction。
通过数据源DataSource来创建Transaction。
事务Transaction的创建
JdbcTransaction
就是JdbcTransaction是使用的java.sql.Connection 上的commit和rollback功能,
JdbcTransaction只是相当于对java.sql.Connection事务处理进行了一次包装(wrapper),
Transaction的事务管理都是通过java.sql.Connection实现的
JdbcTransaction只是相当于对java.sql.Connection事务处理进行了一次包装(wrapper),
Transaction的事务管理都是通过java.sql.Connection实现的
ManagedTransaction
ManagedTransaction让容器来管理事务Transaction的整个生命周期,
意思就是说,使用ManagedTransaction的commit和rollback功能不会对事务有任何的影响,
它什么都不会做,它将事务管理的权利移交给了容器来实现。
意思就是说,使用ManagedTransaction的commit和rollback功能不会对事务有任何的影响,
它什么都不会做,它将事务管理的权利移交给了容器来实现。
缓存
设计原理
一级缓存
什么是一级缓存? 为什么使用一级缓存?
原因:在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,避免查询一次数据库的代价很大,这有可能造成很大的资源浪费。
对于会话(Session)级别的数据缓存,我们称之为一级数据缓存,简称一级缓存。
MyBatis会在一次会话,一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户
mybatis一级缓存示意图
MyBatis中的一级缓存是怎样组织的?(即SqlSession中的缓存是怎样组织的?)
SqlSession对象、Executor对象、Cache对象之间的关系
Session级别的一级缓存实际上就是使用PerpetualCache维护的
PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v> 来实现
PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v> 来实现
一级缓存的生命周期有多长?
MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉
如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用
如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用
SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
SqlSession 一级缓存的工作流程
Cache接口的设计以及CacheKey的定义
Mybatis如何保证两次查询是相同的
(statementId + rowBounds + 传递给JDBC的SQL + 传递给JDBC的参数值)
(statementId + rowBounds + 传递给JDBC的SQL + 传递给JDBC的参数值)
传入的 statementId
查询时要求的结果集中的结果范围 (结果的范围通过rowBounds.offset和rowBounds.limit表示)
MyBatis自身提供的分页功能是通过RowBounds来实现的,它通过rowBounds.offset和rowBounds.limit来过滤查询出来的结果集,
这种分页功能是基于查询结果的再过滤,而不是进行数据库的物理分页
这种分页功能是基于查询结果的再过滤,而不是进行数据库的物理分页
这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )
传递给java.sql.Statement要设置的参数值
CacheKey的hashcode生成算法
本质上是使用的HashMap<k,v>,而构建CacheKey的目的就是为了作为HashMap<k,v>中的key值。
而HashMap是通过key值的hashcode 来组织和存储的,那么,构建CacheKey的过程实际上就是构造其hashCode的过程
而HashMap是通过key值的hashcode 来组织和存储的,那么,构建CacheKey的过程实际上就是构造其hashCode的过程
hashCode生成算法
二级缓存
MyBatis的缓存机制整体设计以及二级缓存的工作模式
MyBatis的二级缓存机制
Mybatis二级缓存工作模式
装饰器模式
CachingExecutor和Executor的接口
MyBatis二级缓存的划分
缓存划分的更细,即是Mapper级别的,即每一个Mapper都可以拥有一个Cache对象
a.为每一个Mapper分配一个Cache缓存对象(使用<cache>节点配置)
b.多个Mapper共用一个Cache缓存对象(使用<cache-ref>节点配置)
使用二级缓存条件
1.MyBatis支持二级缓存的总开关:全局配置变量参数 cacheEnabled=true
2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效
该select语句的参数 useCache=true
<select id="selectByMinSalary" resultMap="BaseResultMap" parameterType="java.util.Map" useCache="true">
一级缓存和二级缓存的使用顺序
二级缓存 ———> 一级缓存——> 数据库
二级缓存实现的选择
MyBatis内部实现了一系列的Cache缓存实现类,并提供了各种缓存刷新策略如LRU,FIFO等等
Mybatis缓存刷新策略
LRU:(Least Recently Used)最近最少使用算法
即如果缓存中容量已经满了,会将缓存中最近做少被使用的缓存记录清除掉,然后添加新的记录;
FIFO:(First in first out),先进先出算法
如果缓存中的容量已经满了,那么会将最先进入缓存中的数据清除掉
Scheduled:指定时间间隔清空算法
以指定的某一个时间间隔将Cache缓存中的数据清空
所有策略
MyBatis还允许用户自定义Cache接口实现,用户是需要实现org.apache.ibatis.cache.Cache接口,
然后将Cache实现类配置在<cache type="">节点的type属性上即可
然后将Cache实现类配置在<cache type="">节点的type属性上即可
MyBatis还支持跟第三方内存缓存库如Memecached的集成
设计模式
设计模式
Builder模式
Builder模式应用1: SqlSessionFactory的创建
Builder模式应用2: 数据库连接环境Environment对象的创建
修饰器模式
CacheExecutor
池化设计原理
框架设计
整体设计
接口层:与数据库的交互方式
接口调用方式:基于Statement ID
接口调用方式:基于Mapper接口
Mapper初始化过程
Mapper调用过程
数据处理层
过程
1. 参数映射和动态SQL语句生成
2. SQL语句执行
3. 结果处理和映射
框架支撑层
事物管理机制
连接池管理机制
缓存机制
核心主件
Configuration
MyBatis所有的配置信息都维持在Configuration对象之中
SqlSessionFactoryBuilder
概念:
SqlsessionFactory构造器
SqlSessionFactoryBuilder的作用就是通过XML或者Java代码来建造一个或者多个工厂(SqlSessionFactory)
生命周期:
一旦完成建造工厂的任务,我们就应该废弃它,回收空间。所以它的生命周期只存在方法局部,完成工厂的建造即结束。
SqlSessionFactory
概念:
SqlSession会话工厂
作用就是创建会话(SqlSession),每次需要访问数据库时,就要通过SqlSessionFactory创建会话
生命周期:
整个mybatis的生命周期
建议:每一个数据库,只对应一个SqlSessionFactory,以此来管理数据资源的分配,防止连接资源被过度消耗
SqlSession
概念:
执行SQL会话
相当于JDBC的connnection
生命周期
在请求数据库处理事务的过程中,存活于一个应用的请求和操作,可以执行多个SQL,保证事务的一致性。
注意事项
线程不安全的对象,在多线程中应当注意数据库的隔离级别和数据库锁等高级特性。并且当SqlSession完成自身工作时需要及时关闭,以防止数据库连接池的活动资源减少,影响系统性能
Executor
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
SQL Mapper
概念:
由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。
ErrorContext日志系统
ExceptionFactory
mybatis层次结构
映射文件
SQL
映射规则
POJO
0 条评论
下一页