目录
- 1. 使用
- 1.1. 新建maven项目
- 1.2. pom.xml
- 1.3. 配置mybatis
- 1.4. 新建mapper
- 1.5. 测试
- 1.6. 项目结构
- 2. 源码分析
- 2.1. 框架分层
- 2.2. 四大对象
- 2.3. 要分析的代码
- 2.4. 获取SqlSessionFactory对象
- 2.4.1. 解析xml配置
- 2.4.1.1. 解析mybatis全局配置
- 2.4.1.2. 解析mapper.xml
- 2.5. 获取sqlsession对象
- 2.5.1. 获取数据库链接信息
- 2.5.2. 创建事务管理工厂
- 2.5.3. 创建Executor
- 2.6. 获取mapper类的代理对象
- 2.6.1. 从MapperRegistry通过mapper名获取MapperProxyFactory
- 2.6.2. 通过MapperProxyFactory使用jdk动态代理创建mapper
- 2.7. 通过代理对象执行CRUD方法
- 2.7.1. 通过MapperMethod执行sql
- 2.7.2. 怎么执行sql的
- 2.7.2.1. 把sql语句封装成MappedStatement
- 2.7.2.2. 通过Executor执行sql
- 2.7.2.2.1. 二级缓存中有则直接返回
- 2.7.2.2.2. 一级缓存中有则直接返回,没有在查数据库
- 2.7.2.2.3. 真正的jdbc操作
- 3. 参考
1. 使用
1.1. 新建maven项目
1.2. pom.xml
- 4.0.0 com.zsk mybatis_test 1.0-SNAPSHOT UTF-8 1.8 1.8 1.8 org.mybatis mybatis 3.5.3 org.postgresql postgresql 42.2.8 org.apache.maven.plugins maven-compiler-plugin 3.7.0 src/main/java **/*.* src/main/resources **/*.* src/main/webapp META-INF/resources **/*.* false
复制代码 1.3. 配置mybatis
- resources/jdbc.properties
- driver=org.postgresql.Driverurl=jdbc:postgresql://localhost:5432/taousername=zskpassword=zskroot
复制代码
- resources/mybatis-config.xml
1.4. 新建mapper
- package com.zsk.model;/** * @description: * @author: zsk * @create: 2019-11-30 15:32 **/public class User{ private Long id; private String username; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + '}'; }}
复制代码- package com.zsk.dao;import com.zsk.model.User;/** * @description: * @author: zsk * @create: 2019-11-30 15:31 **/public interface UserMapper{ User getById(Long id);}
复制代码- select * from tb_user where id = #{id}
复制代码 1.5. 测试
- import com.zsk.dao.UserMapper;import com.zsk.model.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;/** * @description: * @author: zsk * @create: 2019-11-30 15:28 **/public class Main{ public static void main(String[] args) throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.getById(7L); System.out.println(user); } }}
复制代码 1.6. 项目结构
2. 源码分析
目录
- 1. 使用
- 1.1. 新建maven项目
- 1.2. pom.xml
- 1.3. 配置mybatis
- 1.4. 新建mapper
- 1.5. 测试
- 1.6. 项目结构
- 2. 源码分析
- 2.1. 框架分层
- 2.2. 四大对象
- 2.3. 要分析的代码
- 2.4. 获取SqlSessionFactory对象
- 2.4.1. 解析xml配置
- 2.4.1.1. 解析mybatis全局配置
- 2.4.1.2. 解析mapper.xml
- 2.5. 获取sqlsession对象
- 2.5.1. 获取数据库链接信息
- 2.5.2. 创建事务管理工厂
- 2.5.3. 创建Executor
- 2.6. 获取mapper类的代理对象
- 2.6.1. 从MapperRegistry通过mapper名获取MapperProxyFactory
- 2.6.2. 通过MapperProxyFactory使用jdk动态代理创建mapper
- 2.7. 通过代理对象执行CRUD方法
- 2.7.1. 通过MapperMethod执行sql
- 2.7.2. 怎么执行sql的
- 2.7.2.1. 把sql语句封装成MappedStatement
- 2.7.2.2. 通过Executor执行sql
- 2.7.2.2.1. 二级缓存中有则直接返回
- 2.7.2.2.2. 一级缓存中有则直接返回,没有在查数据库
- 2.7.2.2.3. 真正的jdbc操作
- 3. 参考
2.1. 框架分层
2.2. 四大对象
MyBatis创建四大对象的时候,使用动态代理机制添加了拦截器.
- Executor
- ParameterHandler
- ResultSetHandler
- StatementHandler
2.3. 要分析的代码
- public class Test{ public static void main(String[] args) throws Exception { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //1.获取SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2.获取sqlsession对象 SqlSession session = sqlSessionFactory.openSession(); //3.获取接口的代理对象 TtestMapper mapper = session.getMapper(TtestMapper.class); //4.执行CRUD方法 Ttest blog = mapper.getOne(1); System.out.println(blog); session.close(); }}
复制代码 2.4. 获取SqlSessionFactory对象
- new SqlSessionFactoryBuilder().build(inputStream)
- public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { //读取mybatis-config.xml,并把配置信息封装到XMLConfigBuilder XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); //把xml文件中的配置全部封装到Configuraion里面 return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }
复制代码 2.4.1. 解析xml配置
2.4.1.1. 解析mybatis全局配置
- public Configuration parse() { //解析过了直接抛出异常 if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; //通过XPath获取mybatis-config.xml中的configuration节点作为root节点,继续解析下级节点 parseConfiguration(parser.evalNode("/configuration")); return configuration; }private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); //获取settings节点,封装到Properties中 Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); loadCustomLogImpl(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); //把settings节点下的所有属性设置到Configuration中 settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); //解析mappers标签 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } private void settingsElement(Properties props) { //没有的话设置的默认值 configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL"))); configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE"))); configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true)); configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory"))); configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false)); configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false)); configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true)); configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true)); configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false)); configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE"))); configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null)); configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null)); configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false)); configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false)); configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION"))); configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER"))); configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString")); configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true)); configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage"))); configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler"))); configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false)); configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true)); configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false)); configuration.setLogPrefix(props.getProperty("logPrefix")); configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory"))); } private void mapperElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { //有package节点则走下面的逻辑 if ("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { //根据resource,url,class节点确定走那段逻辑 String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); InputStream inputStream = Resources.getResourceAsStream(resource); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); //解析mapper标签 mapperParser.parse(); } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url == null && mapperClass != null) { // //创建class对象加载到configuration中 Class mapperInterface = Resources.classForName(mapperClass); configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }
复制代码 2.4.1.2. 解析mapper.xml
- public void parse() { if (!configuration.isResourceLoaded(resource)) { //mapper标签 configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); bindMapperForNamespace(); } parsePendingResultMaps(); parsePendingCacheRefs(); parsePendingStatements(); } private void configurationElement(XNode context) { try { String namespace = context.getStringAttribute("namespace"); if (namespace == null || namespace.equals("")) { throw new BuilderException("Mapper's namespace cannot be empty"); } builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode("cache-ref")); cacheElement(context.evalNode("cache")); //解析parameterMap,resultMap,sql标签并存放到Configuration中 parameterMapElement(context.evalNodes("/mapper/parameterMap")); resultMapElements(context.evalNodes("/mapper/resultMap")); sqlElement(context.evalNodes("/mapper/sql")); //解析CRUD标签 buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } catch (Exception e) { throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e); } } private void buildStatementFromContext(List list) { if (configuration.getDatabaseId() != null) { buildStatementFromContext(list, configuration.getDatabaseId()); } buildStatementFromContext(list, null);}private void buildStatementFromContext(List list, String requiredDatabaseId) { for (XNode context : list) { final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId); try { statementParser.parseStatementNode(); } catch (IncompleteElementException e) { configuration.addIncompleteStatement(statementParser); } }}public void parseStatementNode() { String id = context.getStringAttribute("id"); String databaseId = context.getStringAttribute("databaseId"); if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) { return; } String nodeName = context.getNode().getNodeName(); SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH)); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect); boolean useCache = context.getBooleanAttribute("useCache", isSelect); boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false); // Include Fragments before parsing XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode()); String parameterType = context.getStringAttribute("parameterType"); Class parameterTypeClass = resolveClass(parameterType); String lang = context.getStringAttribute("lang"); LanguageDriver langDriver = getLanguageDriver(lang); // Parse selectKey after includes and remove them. processSelectKeyNodes(id, parameterTypeClass, langDriver); // Parse the SQL (pre: and were parsed and removed) KeyGenerator keyGenerator; String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX; keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true); if (configuration.hasKeyGenerator(keyStatementId)) { keyGenerator = configuration.getKeyGenerator(keyStatementId); } else { keyGenerator = context.getBooleanAttribute("useGeneratedKeys", configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; } SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass); StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString())); Integer fetchSize = context.getIntAttribute("fetchSize"); Integer timeout = context.getIntAttribute("timeout"); String parameterMap = context.getStringAttribute("parameterMap"); String resultType = context.getStringAttribute("resultType"); Class resultTypeClass = resolveClass(resultType); String resultMap = context.getStringAttribute("resultMap"); String resultSetType = context.getStringAttribute("resultSetType"); ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); String keyProperty = context.getStringAttribute("keyProperty"); String keyColumn = context.getStringAttribute("keyColumn"); String resultSets = context.getStringAttribute("resultSets"); //最终封装成MappedStatement对象 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets); }
复制代码

2.5. 获取sqlsession对象
- DefaultSqlSessionFactory.openSession()
- public class DefaultSqlSessionFactory implements SqlSessionFactory { @Override public SqlSession openSession() { //根据Configuration配置的ExecutorType(默认是SIMPLE)来获取SqlSession return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { //从Configuration中获取数据库链接信息 final Environment environment = configuration.getEnvironment(); //创建事务 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //创建执行器 final Executor executor = configuration.newExecutor(tx, execType); //最后返回的SqlSession包含了Configuration,Executor信息 return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } }
复制代码 2.5.1. 获取数据库链接信息
2.5.2. 创建事务管理工厂
2.5.3. 创建Executor
- public class Configuration { public Executor newExecutor(Transaction transaction, ExecutorType executorType) { //默认是ExecutorType.SIMPLE executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; //根据不同的type创建不同的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); } //装饰器模式:把原始的Executor用Cache包装 if (cacheEnabled) { executor = new CachingExecutor(executor); } //也是装饰器模式?--把所有插件都包装到Executor上 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }}
复制代码 2.5.3.1. Executor继承体系
2.6. 获取mapper类的代理对象
- DefaultSqlSession.getMapper(TtestMapper.class)
- @Override public T getMapper(Class type) { //调用Configuration的getMapper方法 return configuration.getMapper(type, this); }
复制代码 2.6.1. 从MapperRegistry通过mapper名获取MapperProxyFactory
- public T getMapper(Class type, SqlSession sqlSession) { //调用MapperRegistry(存储了Mapper名:MapperProxyFactory)的getMapper方法 return mapperRegistry.getMapper(type, sqlSession); }
复制代码- @SuppressWarnings("unchecked") public T getMapper(Class type, SqlSession sqlSession) { //从Map> knownMappers = new HashMap();获取MapperProxyFactory final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) knownMappers.get(type); //没找到则抛出异常 if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
复制代码 2.6.2. 通过MapperProxyFactory使用jdk动态代理创建mapper
- public T newInstance(SqlSession sqlSession) { //class MapperProxy implements InvocationHandler,JDK的动态代理接口 final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } @SuppressWarnings("unchecked") protected T newInstance(MapperProxy mapperProxy) { //参数:被代理对象的类加载器,被代理对象实现的接口,对立对象实例 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
复制代码 2.7. 通过代理对象执行CRUD方法
- //调用的是代理类的invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { //如果这个方法是Object类的方法,那么直接调用 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); //判断是否接口的方法 } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } //从缓存中获取MapperMethod final MapperMethod mapperMethod = cachedMapperMethod(method); //执行sql语句 return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) { //Map中有这个方法的话直接返回,没有则new返回 return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); }
复制代码 2.7.1. 通过MapperMethod执行sql
- public class MapperMethod { private final SqlCommand command; private final MethodSignature method; public MapperMethod(Class mapperInterface, Method method, Configuration config) { //封装sql语句 this.command = new SqlCommand(config, mapperInterface, method); //封装sql语句的参数 this.method = new MethodSignature(config, mapperInterface, method); } public Object execute(SqlSession sqlSession, Object[] args) { Object result; //根据sql语句的类型调用CRUD switch (command.getType()) { case INSERT: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } case UPDATE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); break; } case DELETE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } case SELECT: //没有返回值 if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; //返回多个 } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); //返回ma } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); //返回游标--分页? } else if (method.returnsCursor()) { result = executeForCursor(sqlSession, args); //返回一个 } else { Object param = method.convertArgsToSqlCommandParam(args); //调用SqlSession的selectOne result = sqlSession.selectOne(command.getName(), param); if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { result = Optional.ofNullable(result); } } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; }}
复制代码 2.7.2. 怎么执行sql的
- @Override public T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. //都是调用的list方法 List list = this.selectList(statement, parameter); //一个的话直接返回 if (list.size() == 1) { return list.get(0); //多个的话有问题,抛出异常 } else if (list.size() > 1) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); //一个都没有返回null } else { return null; } } @Override public List selectList(String statement, Object parameter) { return this.selectList(statement, parameter, RowBounds.DEFAULT); } @Override public List selectList(String statement, Object parameter, RowBounds rowBounds) { try { //调用Configuration把sql和参数封装成MapperStatement MappedStatement ms = configuration.getMappedStatement(statement); //通过执行器来执行 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
复制代码 2.7.2.1. 把sql语句封装成MappedStatement
- public MappedStatement getMappedStatement(String id) { return this.getMappedStatement(id, true); } public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) { //没有生成过这条语句则重新构建在放入map if (validateIncompleteStatements) { buildAllStatements(); } //从map中取出这条语句,防止反复解析 return mappedStatements.get(id); }
复制代码 2.7.2.2. 通过Executor执行sql
2.7.2.2.1. 二级缓存中有则直接返回
- @Override public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //取出sql BoundSql boundSql = ms.getBoundSql(parameterObject); //构造缓存的key CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } @Override public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); //缓存中有 if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") //从缓存中取 List list = (List) tcm.getObject(cache, key); //取出的为空 if (list == null) { //重新执行sql,再次放入缓存 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } //BaseExecutor的query方法 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
复制代码 2.7.2.2.2. 一级缓存中有则直接返回,没有在查数据库
- @SuppressWarnings("unchecked") @Override public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List list; try { queryStack++; //一级缓存? list = resultHandler == null ? (List) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //从数据库中查 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; } private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { //SimpleExecutor list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
复制代码 2.7.2.2.3. 真正的jdbc操作
- @Override public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); //JDBC操作 stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
复制代码 3. 参考
- mybatis – MyBatis 3 | Introduction
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除 |