加载数据库驱动
创建数据库连接
创建预执行语句
代码重复耦合度高;
数据库配置信息和sql配置信息硬编码,操作不便;
提供数据库连接信息配置文件
提供sql配置文件:crud的配置文件,要包括查询参数、返回值类型、sql语句
根据配置文件绝对路径,读取成字节流InputStream到内存中;
创建Resources工具类将配置文件读取为指定格式到内存中;
创建SqlSessionFactoryBuilder工厂类。利用建造者模式生产SqlSessionFactory;
类方法:build(inputStream);创建者模式,多种组合方式;
创建SqlSessionFactory接口及其实现类DefaultSqlSession,生产SqlSession对象;
接口方法:openSession();生产SqlSession对象;
创建SqlSession接口及其实现类DefaultSqlSession对象,执行封装的jdbc操作;
接口方法:selectList();selectOne();
创建Executor接口及其实现类SimpleExecutor,执行具体jdbc操作;
接口方法:query(Configuration,MappedStatement,Object…params);
## 部分属性
protected Environment environment;
protected boolean aggressiveLazyLoading; //懒加载配置
protected boolean cacheEnabled; //是否开启二级缓存
protected boolean lazyLoadingEnabled; //懒加载配置
protected Class<?> configurationFactory;
protected final MapperRegistry mapperRegistry; // 二级缓存管理类
protected final InterceptorChain interceptorChain;
protected final TypeHandlerRegistry typeHandlerRegistry; //类型转换器配置
protected final TypeAliasRegistry typeAliasRegistry;
protected final LanguageDriverRegistry languageRegistry;
protected final Map<String, MappedStatement> mappedStatements; //语句对象集合
protected final Map<String, Cache> caches; //二级缓存需要使用
protected final Map<String, ResultMap> resultMaps;
protected final Map<String, ParameterMap> parameterMaps;
protected final Map<String, KeyGenerator> keyGenerators;
protected final Set<String> loadedResources;
protected final Map<String, XNode> sqlFragments;
protected final Collection<XMLStatementBuilder> incompleteStatements; //未完成的xml语句解析
protected final Collection<CacheRefResolver> incompleteCacheRefs;
protected final Collection<ResultMapResolver> incompleteResultMaps;
protected final Collection<MethodResolver> incompleteMethods;
protected final Map<String, String> cacheRefMap; //标签解析结果
protected ProxyFactory proxyFactory; //mapper代理工程
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b0Ao10d9-1636810845875)(/Users/yjwu/Desktop/image-20211113163951438.png)]
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
public interface SqlSession extends Closeable {
<T> T selectOne(String var1);
<T> T selectOne(String var1, Object var2);
<E> List<E> selectList(String var1);
<E> List<E> selectList(String var1, Object var2);
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<K, V> Map<K, V> selectMap(String var1, String var2);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
<T> Cursor<T> selectCursor(String var1);
<T> Cursor<T> selectCursor(String var1, Object var2);
<T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
int insert(String var1);
int insert(String var1, Object var2);
int update(String var1);
int update(String var1, Object var2);
int delete(String var1);
int delete(String var1, Object var2);
void commit();
void commit(boolean var1);
void rollback();
void rollback(boolean var1);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> var1);
Connection getConnection();
}
过程
1、根据statement的id,创建了MappedStatement对象;
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
List var6;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
var6 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, handler);
} catch (Exception var10) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var10, var10);
} finally {
ErrorContext.instance().reset();
}
return var6;
}
2、调用executor.query()、executor.update();
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement var1, Object var2) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean var1) throws SQLException;
void rollback(boolean var1) throws SQLException;
CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);
boolean isCached(MappedStatement var1, CacheKey var2);
void clearLocalCache();
void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);
Transaction getTransaction();
void close(boolean var1);
boolean isClosed();
void setExecutorWrapper(Executor var1);
}
BaseExecutor
BaseExecutor.query();
1、根据MappedStatement对象获取BoundSql;根据ms、parameters、rowBounds、boundSql创建CacheKey对象;
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
2、继续调用BaseExecutor.query()重载方法:判断是否需要清除一级缓存,是则清除;然后从缓存中获取数据,未获取到数据则继续调用queryFromDatabase(), 进而继续调用其子类doQuery()方法。然后将查询的结果放入到一级缓存中,最后返回数据。
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
this.localCache.removeObject(key);
}
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
3、this.doQuery() 是抽象方法,实际调用子类SimpleExecutor.doQuery();
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = this.prepareStatement(handler, ms.getStatementLog());
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
CachingExecutor
CachingExecutor.query();
1、获取MappedStatement的Cache对象,判断二级缓存TransactionalManager中是否含有Cache为大key、cacheKey为小key的数据;有则返回,否则进行数据库查询;
2、调用BaseExecutor.query();
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
this.flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
this.ensureNoOutParams(ms, boundSql);
List<E> list = (List)this.tcm.getObject(cache, key);
if (list == null) {
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
this.tcm.putObject(cache, key, list);
}
return list;
}
}
// 调用BaseExecutor.query();然后过程和未开启缓存一样;
return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
public interface StatementHandler {
Statement prepare(Connection var1, Integer var2) throws SQLException;
void parameterize(Statement var1) throws SQLException;
void batch(Statement var1) throws SQLException;
int update(Statement var1) throws SQLException;
<E> List<E> query(Statement var1, ResultHandler var2) throws SQLException;
<E> Cursor<E> queryCursor(Statement var1) throws SQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler();
}
1、BaseStatementHandler.prepare(); 创建statement对象;
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(this.boundSql.getSql());
Statement statement = null;
try {
statement = this.instantiateStatement(connection);
this.setStatementTimeout(statement, transactionTimeout);
this.setFetchSize(statement);
return statement;
} catch (SQLException var5) {
this.closeStatement(statement);
throw var5;
} catch (Exception var6) {
this.closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + var6, var6);
}
}
BaseStatementHandler.prepare();
调用instantiateStatement(),由子类重写,进而创建statement对象。
SimpleStatementHandler.instantiateStatement();
connection.createStatement()创建statement对象。
PreparedStatementHandler.instantiateStatement();
connection.prepareStatement()创建statement对象
2、设置preparedStatement的参数;
PreparedStatementHandler.parameterize();
调用paramenterHandler.setParameters()设置参数;
public void parameterize(Statement statement) throws SQLException {
this.parameterHandler.setParameters((PreparedStatement)statement);
}
3、执行sql并处理查询结果;
聊聊MyBatis缓存机制 - 美团技术团队 (meituan.com)
一二级缓存是底层数据结构都是hashmap,key=namespace:sqlid:params:sql:分页参数
一级缓存
默认开启,SqlSession级别,不同SqlSession之间隔离,当执行commit、rollback操作后就会清空;
一级缓存缓存的是结果对象,同一SqlSession多次查询的结果是同一个对象;
一级缓存可能会发生脏读,一个sqlsession命中缓存,无法读取到另一个sqlsession更新后的数据。
PreputalCache实现了mybatis中的cache接口,底层数据结构是HashMap。
BaseExecutor的构造方法中,实例化PreputalCache类型的localCache变量。此后,由BaseExecutor完成的query()查询,会先从localCache中获取对象;获取不到,才会调用queryFromDatabase()从数据库中查询,当查询到结果后先放入到localCache中再返回。
二级缓存
作用域是namespace级别,默认关闭,需要全局配置开启;mapper可以配置标签设置该namespace下二级缓存的刷新算法、刷新周期、存储对象的个数、缓存是否只读;同时,每个查询语句可以单独配置useCache=false设置二级缓存的关闭,设置flush=true开启刷新缓存(默认开启,一般地,commit操作后都会刷新缓存)。如果使用注解开发,可以在mapper接口上使用@ CacheNamespac注解进行相关配置,该注解还可以配置自定义缓存的实现类,在sql注解上使用@ option(usecache=false)关闭二级缓存,
因为二级缓存缓存的是结果的值,可能保存在内存、磁盘中,所以缓存对象必须实现序列化,这样才能从二级缓存中进行查询后通过反序列化返回。
CachingExecutor类使用BaseExecutor类完成实际的jdbc操作,其内部通过TransactionalCacheManager类来进行二级缓存的管理。该tcm变量的key为Cache接口的实现类,实际值为MappedStatement(查询语句)中Cache类型的cache变量;进而等同于Configuration中HashMap类型的caches成员变量中的一个value,而caches变量的key即解析sql配置文件时,从标签中解析出来的namespace值,默认即为namespace值。所以同一个namespace下的语句,他们再tcm中是同一个key
二级缓存以hashMap存储数据,无法实现分布式缓存;
拦截器;intercepts注解、signature注解;
defaultSqlSession不是线程安全的,所以不能使用单例模式。sqlSessionFactory每次都创建一个新的sqlSession对象。SqlSessionTemplate是线程安全的,TransactionSynchronizationManager通过map缓存,key为SqlSessionFactyory,从中获取;SqlSessionManager是线程安全的,通过threadLocal实现。