蘑菇街的网站建设,天津室内设计公司排名,网站设计制作报价图片欣赏,如何开展网站推广从之前的文章#xff0c;我们知道了其实mapper真正执行的方法就下面的最后两行。#xff08;以下所有的分析都基于一次mybatis的一次select查询。
MapperProxy类中的invoke函数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {i…从之前的文章我们知道了其实mapper真正执行的方法就下面的最后两行。以下所有的分析都基于一次mybatis的一次select查询。
MapperProxy类中的invoke函数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {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);//执行查询并且返回结果return mapperMethod.execute(sqlSession, args);}MapperMthod private MapperMethod cachedMapperMethod(Method method) {//methodCache其实就是一个缓存将方法与mapperMethod作为一组键值对进行缓存MapperMethod mapperMethod methodCache.get(method);//若缓存中没找到则生成一个在把生成的mapperMethod加入缓存if (mapperMethod null) {//生成mapperMethod的方法mapperMethod new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());methodCache.put(method, mapperMethod);}return mapperMethod;}这里解释一下mapperMethod有什么作用首先看一下MapperMethod类的具体参数
public class MapperMethod {//记录方法是什么类型的方法UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;private final SqlCommand command;//记录方法的具体情况比如说返回一个还是多个方法返回类型方法的参数是啥等信息private final MethodSignature method;//MapperMethod的构造函数public MapperMethod(Class? mapperInterface, Method method, Configuration config) {this.command new SqlCommand(config, mapperInterface, method);this.method new MethodSignature(config, mapperInterface, method);}}//执行方法public Object execute(SqlSession sqlSession, Object[] args) {Object result;//通过command的类型去找实际需要执行的方法不一个个分析了只以select的executeForMany为例子//其他都是差不了多少的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);} else if (method.returnsMap()) {result executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result executeForCursor(sqlSession, args);} else {Object param method.convertArgsToSqlCommandParam(args);result sqlSession.selectOne(command.getName(), param);}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;}//查询方法private E Object executeForMany(SqlSession sqlSession, Object[] args) {ListE result;//Object param method.convertArgsToSqlCommandParam(args);//是否需要分页if (method.hasRowBounds()) {//拿到rowBoundsRowBounds rowBounds method.extractRowBounds(args);//查询result sqlSession.EselectList(command.getName(), param, rowBounds);} else {//查询进入这条result sqlSession.EselectList(command.getName(), param);}// issue #510 Collections arrays supportif (!method.getReturnType().isAssignableFrom(result.getClass())) {if (method.getReturnType().isArray()) {return convertToArray(result);} else {return convertToDeclaredCollection(sqlSession.getConfiguration(), result);}}return result;}//实际还是走的有RowBounds 的语句只是给了默认值默认值是拿到Integer的最大值Overridepublic E ListE selectList(String statement, Object parameter) {return this.selectList(statement, parameter, RowBounds.DEFAULT);}Overridepublic E ListE selectList(String statement, Object parameter, RowBounds rowBounds) {try {//从configuration获取MappedStatement 在初始化的时候就已经放到缓存中了这里只是获取一下MappedStatement ms configuration.getMappedStatement(statement);//通过executor来查询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();}}因为mybatis默认开始Cache所以我们的Executor是CachingExecutor。但是我们没在mapper.xml中配置Cache的属性所以最终是没缓存功能的。通过装饰器模式来增加了Executor的功能
Executor
//这两个方法是CachingExecutor里面的Overridepublic E ListE query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {//生成BoundSql里面存放着sql语句BoundSql boundSql ms.getBoundSql(parameterObject);//生成缓存用的keyCacheKey key createCacheKey(ms, parameterObject, rowBounds, boundSql);return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}Overridepublic E ListE query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)throws SQLException {//因为mapper中没有配置cache所以这里的cahce是没有的Cache cache ms.getCache();//cache为空所以不会走这里面的逻辑if (cache ! null) {flushCacheIfRequired(ms);if (ms.isUseCache() resultHandler null) {ensureNoOutParams(ms, parameterObject, boundSql);SuppressWarnings(unchecked)ListE list (ListE) tcm.getObject(cache, key);if (list null) {list delegate.E query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);tcm.putObject(cache, key, list); // issue #578 and #116}return list;}}//到来这里通过delegate来执行query因为CachingExecutor是一个装饰类delegate是原始类在这里是SimpleExecutorreturn delegate.E query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}SuppressWarnings(unchecked)Overridepublic E ListE 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();}ListE list;try {queryStack;//这里的localCache是一级缓存是在BaseExecutor中的list resultHandler null ? (ListE) 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 #601deferredLoads.clear();if (configuration.getLocalCacheScope() LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list;}private E ListE queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {ListE list;//先从key中放个占位的值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.putObject(key, parameter);}return list;}Overridepublic E ListE doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt null;try {Configuration configuration ms.getConfiguration();//生成一个StatementHandler对Statement进行处理StatementHandler handler configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//生成statementstmt prepareStatement(handler, ms.getStatementLog());//进行访问return handler.Equery(stmt, resultHandler);} finally {closeStatement(stmt);}}//这里是prepareStatement函数用来生成访问数据库需要的Statement对象private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Statement stmt;//如果是debug状态则对sqlSession进行代理因为要打印logConnection connection getConnection(statementLog);//stmt handler.prepare(connection, transaction.getTimeout());//对参数进行处理handler.parameterize(stmt);return stmt;}我们进handler的prepare方法看看 Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement null;try {//初始化statement statement instantiateStatement(connection);//设置超时setStatementTimeout(statement, transactionTimeout);//设置fetchSize(mysql不起作用不支持这个)setFetchSize(statement);return statement;} catch (SQLException e) {closeStatement(statement);throw e;} catch (Exception e) {closeStatement(statement);throw new ExecutorException(Error preparing statement. Cause: e, e);}}之后得到了Statement对象后要去访问数据库了。上面的return handler.query(stmt, resultHandler);调用的是下面的query方法 Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {return delegate.Equery(statement, resultHandler);}1234Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {//将Statement强转成PreparedStatementPreparedStatement ps (PreparedStatement) statement;//对数据库进行查询对数据库进行查询是jdbc做的事情mybatis也只是对jdbc进行了包装ps.execute();//对返回结果进行处理return resultSetHandler.E handleResultSets(ps);}到这里我们就进行了一次对数据库的访问并拿到了数据。数据此时在Statement的ResultSet里面 如果你熟悉jdbc的话一定不陌生下面的代码我们拿到resultSet后的处理方式如下。 ResultSet resultSet preparedStatement.executeQuery();while(resultSet.next()) {String string resultSet.getString(1);}