mybatis源码执行流程,mybatis操作数据库的原理

  mybatis源码执行流程,mybatis操作数据库的原理

  

目录

1 SQL语句的执行过程介绍2 SQL执行的入口分析2.1 为制图人接口创建代理对象2.2 执行代理逻辑3查询语句的执行过程分析3.1选择一个方法分析3.2 sql获取3.3 参数设置3.4 SQL执行和结果集的封装四更新语句的执行过程分析4.1 sqlsession增删改方法分析4.2 sql获取4.3 参数设置4.4 SQL执行5小结

 

  

1 SQL语句的执行过程介绍

米巴提斯核心执行组件:

 

  

2 SQL执行的入口分析

 

  

2.1 为Mapper接口创建代理对象

//方式1:用户用户=会话。选择一个( com。老鲁。道。用户映射器。通过id 查找用户,101);//方式2:用户映射器映射器=会话。获取映射器(用户映射器。类);ListUser userList=mapper。find all();

 

  

2.2 执行代理逻辑

方式一入口分析:会话是DefaultSqlSession类型的,因为会话工厂默认生成的使用是DefaultSqlSession类型选择一个()会调用选择列表()。

 

  //DefaultSqlSession类公共电子列表选择列表(字符串语句,对象参数,RowBoundsrowBounds){ try { mapped statement ms=configuration。getmapped语句(语句);//凝乳操作是交给Excetor去处理的返回executor.query(ms,wrapCollection(parameter),rowBounds,executor .否_结果_处理程序);} catch(Exception e){ throw异常工厂。包装异常(查询数据库时出错Cause: e,e);}最后{ ErrorContext.instance().reset();}}方式注射毒品入口分析:获取代理对象:

  //DefaultSqlSession类======================@覆盖public T T get mapper(ClassT type){返回配置。get mapper(类型,this);}//配置类===================public T T get mapper(class T type,SQL session SQL session){返回映射器注册表。获取映射器(类型,SQL会话);}//MapperRegistry-apperproxyfactory。新实例====================public T T get mapper(ClassT type,SqlSession sqlSession) { //从缓存中获取该制图人接口的代理工厂对象最终MapperProxyFactoryT mapperProxyFactory=(MapperProxyFactoryT)known mappers。get(类型);//如果该制图人接口没有注册过,则抛异常if(mapperProxyFactory==null){抛出新的绑定异常( Type Type对于地图登记是未知的。);}试试{ //【使用代理工厂创建制图人接口的代理对象】返回mapperproxyfactory。新实例(SQL会话);} catch(Exception e){抛出新的绑定异常(

  Error getting mapper instance. Cause: " + e,e); }}//MapperProxyFactory --->此时生成代理对象 ====================>protected T newInstance(MapperProxy<T> mapperProxy) { //Mybatis底层是调用JDK的Proxy类来创建代理实例 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), newClass[] { mapperInterface }, mapperProxy);}public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession,mapperInterface, methodCache); return newInstance(mapperProxy);}代理对象执行逻辑:

  

//MapperProxy ====================>/**代理对象执行的方法,代理以后,所有Mapper的方法调用时,都会调用这个invoke方法*/public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable { try { if (Object.class.equals(method.getDeclaringClass())) { //如果是Object方法,则调用方法本身 return method.invoke(this, args); } else { //调用接口方法:根据被调用接口的Method对象,从缓存中获取MapperMethodInvoker对象 //apper接口中的每一个方法都对应一个MapperMethodInvoker对象,而MapperMethodInvoker对象里面的MapperMethod保存着对应的SQL信息和返回类型以完成SQL调用 ... return cachedInvoker(method).invoke(proxy, method, args, sqlSession); }} catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t);}}/**获取缓存中MapperMethodInvoker,如果没有则创建一个,而MapperMethodInvoker内部封装这一个MethodHandler*/private MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try { return methodCache.computeIfAbsent(method, m -> { if (m.isDefault()) { //如果调用接口的是默认方法(default方法) try { if (privateLookupInMethod == null) { return newDefaultMethodInvoker(getMethodHandleJava8(method)); } else { return newDefaultMethodInvoker(getMethodHandleJava9(method)); } } catch (IllegalAccessException InstantiationException InvocationTargetException NoSuchMethodException e) { throw new RuntimeException(e); } } else { //如果调用的普通方法(非default方法),则创建一个PlainMethodInvoker并放入缓存,其中MapperMethod保存对应接口方法的SQL以及入参和出参的数据类型等信息 return new PlainMethodInvoker(new MapperMethod(mapperInterface,method, sqlSession.getConfiguration())); } }); } catch (RuntimeException re) { Throwable cause = re.getCause();throw cause == null ? re : cause; }}// MapperProxy内部类: PainMethodInvoker ====================>// 当cacheInvoker返回了PalinMethodInvoker实例之后,紧接着调用了这个实例的PlainMethodInvoker:invoke方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args, SqlSessionsqlSession) throws Throwable { //Mybatis实现接口方法的核心: MapperMethod::execute方法: return mapperMethod.execute(sqlSession, args);}// MapperMethod ====================>public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) { case INSERT: { // 将args进行解析,如果是多个参数则,则根据@Param注解指定名称将参数转换为Map,如果是封装实体则不转换 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 { //解析参数,因为SqlSession::selectOne方法参数只能传入一个,但是我们Mapper中可能传入多个参数, //有可能是通过@Param注解指定参数名,所以这里需要将Mapper接口方法中的多个参数转化为一个ParamMap, //也就是说如果是传入的单个封装实体,那么直接返回出来;如果传入的是多个参数,实际上都转换成了Map Object param = method.convertArgsToSqlCommandParam(args); //可以看到动态代理最后还是使用SqlSession操作数据库的 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 methodwith a primitive return type (" + method.getReturnType() + ")."); } return result;}// 此时我们发现: 回到了sqlsession中private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { List<E> result; Object param = method.convertArgsToSqlCommandParam(args); if (method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.selectList(command.getName(), param, rowBounds); } else { result = sqlSession.selectList(command.getName(), param); } // ... return result;}

 

  

 

  

3 查询语句的执行过程分析

 

  

3.1 selectOne方法分析

// DefaultSqlSession类 ===============>// selectOne@Overridepublic <T> T selectOne(String statement, Object parameter) { // //selectOne()会调用selectList()。 List<T> 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 bereturned by selectOne(), but found: " + list.size()); } else { return null; }}// selectListpublic <E> List<E> selectList(String statement, Object parameter, RowBoundsrowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); // CURD操作是交给Excetor去处理的 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(); }}

 

  

3.2 sql获取

// CachingExecutor ===============>public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBoundsrowBounds, ResultHandler resultHandler) throws SQLException { // 获取绑定的sql命令,比如"SELECT * FROM xxx" BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}@Overridepublic <E> List<E> query(MappedStatement ms, Object parameterObject, RowBoundsrowBounds, 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<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);}//真正执行query操作的是SimplyExecutor代理来完成的,SimplyExecutor的父类BaseExecutor的query方法中:// BaseExecutor类:SimplyExecutor的父类 =================>@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBoundsrowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throwsSQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing aquery").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; //localCache是一级缓存,如果找不到就调用queryFromDatabase从数据库中查找 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); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { clearLocalCache(); }} return list;}//第一次,没有缓存,所以会调用queryFromDatabase方法来执行查询。private <E> List<E> queryFromDatabase(...) 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.putObject(key, parameter); } return list;}// SimpleExecutor类 ============================>public <E> List<E> doQuery(...) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(....); // 1:SQL查询参数的设置 stmt = prepareStatement(handler, ms.getStatementLog()); // StatementHandler封装了Statement // 2:SQL查询操作和结果集的封装 return handler.<E>query(stmt); } finally { closeStatement(stmt); }}

 

  

3.3 参数设置

// SimplyExecutor类 ============================>// 【1】 参数设置: prepareStatementprivate Statement prepareStatement(StatementHandler handler, Log statementLog)throws SQLException { Statement stmt; // 通过getConnection方法来获取一个Connection, Connection connection = getConnection(statementLog); // 调用prepare方法来获取一个Statement stmt = handler.prepare(connection, transaction.getTimeout()); // 设置SQL查询中的参数值 *** handler.parameterize(stmt); return stmt;}// RoutingStatementHandler ============================>// PreparedStatementHandler ============================>@Overridepublic void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement);}// DefaultParameterHandler ============================> 此时参数设置成功@Overridepublic void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("settingparameters").object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if(typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject =configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException SQLException e) { throw new TypeException("Could not set parameters formapping....."); } } } }}

 

  

3.4 SQL执行和结果集的封装

// RoutingStatementHandler ============================>@Overridepublic <E> List<E> query(Statement statement) throws SQLException { return delegate.<E>query(statement);}// PreparedStatementHandler ============================>@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException { // 这里就到了熟悉的PreparedStatement了 PreparedStatement ps = (PreparedStatement) statement; // 执行SQL查询操作 ps.execute(); // 结果交给ResultHandler来处理 return resultSetHandler.<E> handleResultSets(ps);}// DefaultResultSetHandler类(封装返回值,将查询结果封装成Object对象)@Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handlingresults").object(mappedStatement.getId()); final List<Object> multipleResults = new ArrayList<Object>(); int resultSetCount = 0; ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping =nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap =configuration.getResultMap(nestedResultMapId); handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } return collapseSingleResultList(multipleResults);}

 

  

 

  

4 更新语句的执行过程分析

xecutor 的 update 方法分析insert、update 和 delete 操作都会清空一二级缓存doUpdate 方法PreparedStatementHandler 的 update 方法默认是创建PreparedStatementHandler,然后执行prepareStatement方法。执行结果为受影响行数执行更新语句的SQL

 

  

4.1 sqlsession增删改方法分析

// DefaultSqlSession ===============>@Override public int insert(...) { return update(statement, parameter);} @Override public int update(String statement) { return update(statement, null);} @Override public int delete(...) { return update(....);}// insert 、delete操作是通过调用update语句进行的相关逻辑 @Override public int update(String statement, Object parameter) { try { dirty = true; MappedStatement ms = configuration.getMappedStatement(statement); // 增删改 最终底层都是 update return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " +e, e); } finally { ErrorContext.instance().reset(); }}

 

  

4.2 sql获取

// CachingExecutor ===============>@Overridepublic int update(MappedStatement ms, Object parameterObject) throwsSQLException { // 执行增删改,清除缓存 flushCacheIfRequired(ms); // 跳转BaseExecutor return delegate.update(ms, parameterObject);}// BaseExecutor ===============>@Overridepublic int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing anupdate").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } // 清除 LocalCache 一级缓存 clearLocalCache(); //执行 doUpdate return doUpdate(ms, parameter);}// SimpleExecutor ===============>// doUpdate@Overridepublic int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(...); // 【1】.获取statement,并进行参数映射 stmt = prepareStatement(handler, ms.getStatementLog()); // 【2】.handler.update()方法执行具体sql指令 return handler.update(stmt); } finally { closeStatement(stmt); }}

 

  

4.3 参数设置

// SimplyExecutor类 ============================>//【1】 prepareStatementprivate Statement prepareStatement(StatementHandler handler, Log statementLog)throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); // 使用connection对象信息创建statement,并将超时时间绑定 stmt = handler.prepare(connection, transaction.getTimeout()); // parameterize方法设置sql执行时候需要的参数 handler.parameterize(stmt); return stmt;}// RoutingStatementHandler ============================>// PreparedStatementHandler ============================>@Overridepublic void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement);}// DefaultParameterHandler ============================> 此时参数设置成功@Overridepublic void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("settingparameters").object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if(typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject =configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null&      

	  
	  
	  
	  
	  
	  
        

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • 关系型数据库与非关系型数据库简介一样吗,关系型数据库非关系型数据库有哪些
  • 关系型数据库与非关系型数据库简介一样吗,关系型数据库非关系型数据库有哪些,关系型数据库与非关系型数据库简介
  • 关于redis数据库入门详细介绍图片,redis数据库的使用,关于Redis数据库入门详细介绍
  • 使用php连接mysql数据库,php连接数据库的方法
  • 使用php连接mysql数据库,php连接数据库的方法,一文详解PHP连接MySQL数据库的三种方式
  • 什么是分库分表,为什么要进行分库分表-,分库分表的区别,数据库分库分表是什么,什么情况下需要用分库分表
  • vb中adodb连接数据库,
  • treeview控件绑定数据,wpf treeview数据绑定,详解TreeView绑定数据库
  • sql的多表查询,数据库如何实现多表查询
  • SQL数据库的图形管理界面工具是,sql图形界面创建数据库
  • SQL数据库的图形管理界面工具是,sql图形界面创建数据库,SQLServer2019 数据库的基本使用之图形化界面操作的实现
  • sql数据库定时备份怎么弄,mysql 定期备份
  • sql数据库定时备份怎么弄,mysql 定期备份,MySQL 数据库定时备份的几种方式(全面)
  • sqlserver的nvarchar和varchar,数据库varchar和nvarchar
  • sqlserver的nvarchar和varchar,数据库varchar和nvarchar,SQL中varchar和nvarchar的基本介绍及其区别
  • 留言与评论(共有 条评论)
       
    验证码: