Mybatis
初始化流程
//初始化
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("config.xml"));
-
new一个构建者
public class SqlSessionFactoryBuilder { public SqlSessionFactory build(Reader reader, String environment, Properties properties) public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) public SqlSessionFactory build(Configuration config) }
构建者提供了字节流,字符流,配置类以及他们的重载方法,用于构建session工厂
-
工厂内使用一个XML配置构建器,解析配置文件,并返回DefaultSqlSessionFactory
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); //返回DefaultSqlSessionFactory return new DefaultSqlSessionFactory(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { inputStream.close(); } }
使用
SqlSession sqlSession = sqlSessionFactory.openSession();
User o = sqlSession.selectOne("usermapper.selectOne");
-
开启一个session
private SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { try { //获取环境变量 Environment environment = configuration.getEnvironment(); //获取事务工厂 TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); //返回一个链接的包装类 Transaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //返回一个执行器 Executor executor = configuration.newExecutor(tx, execType); //返回DefaultSqlSession (配置信息,执行器,是否自动提交) return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } }
-
Transaction类是什么
/** 包装数据库链接,处理他们的生命周期,包括创建,提交,回滚,关闭. */ public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; Integer getTimeout() throws SQLException; }
-
new Executor()做了什么
protected boolean cacheEnabled = true; 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); } //cacheEnabled默认为true 默认为开启缓存 if (cacheEnabled) { executor = new CachingExecutor(executor); } //使用拦截器对其进行处理 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
-
-
selectOne()
public <T> T selectOne(String statement, Object parameter) { List<T> list = this.selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { //too many } else { return null; } }
-
selectOne 使用 selectList 来实现
-
传入一个全局唯一ID
mybatis需要知道你具体想要执行的语句,也就是我们在配置文件中配置或者注解配置的语句,这是我们和mybatis的一种约定,使用配置文件中根标签的namespace+执行语句的id,作为全局唯一的ID
-
-
selectList()
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { //获取执行信息 MappedStatement ms = configuration.getMappedStatement(statement); //执行查询 return executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { } }
-
这里的执行的executor就是前面返回的CachingExecutor
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //这里是对Sql的解析,BoundSql中包含具体要执行的Sql,传入的参数,返回的参数等... BoundSql boundSql = ms.getBoundSql(parameterObject); //计算缓存的key CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); //查询 return 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 { //从Statement获取二级缓存 Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); //判断当前Statement是否开启了二级缓存 if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); //从二级缓存获取数据 List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { //二级缓存没有数据的时候执行查询 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //放入二级缓存 tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } //没有开启二级缓存执行查询 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
- 从这里可以发现mybatis如果开启了二级缓存是优先使用二级缓存中的数据的
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; try { //在一级缓存中查找 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { //找到了直接处理返回结果 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //没找到的话从数据库中查询 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } return list; }
- 从数据库中查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; //缓存中放入一个占位符 这个占位符和延迟加载存在关系 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { //执行真正的查询 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { //删除占位符 localCache.removeObject(key); } //放入一级缓存 localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { //返回结果的缓存 一级缓存由localOutputParameterCache和localCache构成 localOutputParameterCache.putObject(key, parameter) } return list; }
- 从缓存中查询
private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { //直接取返回结果的缓存 final Object cachedParameter = localOutputParameterCache.getObject(key); //处理返回 if (cachedParameter != null && parameter != null) { metaParameter.setValue(parameterName, cachedValue); } } }
- 从这里可以发现,一级缓存的实现是使用的语句执行结果进行处理返回.
- 从前面的二级缓存代码处可以看到,二级缓存是直接使用处理后的结果.
- 此处两个缓存不同.
-