- 构建 SqlFactory 过程:
- SqlFactory 的核心功能就是提供创建 MyBatis 的核心接口 SqlSession. SqlSession 采用建造者模式进行构建:
- 首先通过 org.apache.ibatis.builder.xml.XMLConfigBuilder 解析配置的 XML 文件, 读出所配置的参数, 并将读取的内容存入 org.apache.ibatis.session.Configuration 类对象中. Configuration 对象采用的是单例模式.
- 通过 Configuration 对象去创建 SqlSessionFactory. SqlSessionFactory 是一个接口, MyBatis 提供了一个默认的实现类 org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.
配置 TypeHandler 都会被注册到 typeHandlerRegistry 对象中去, 而 typeHandlerRegistry 是定义在 XMLConfigBuilder 的父类 BaseBuilder 中的private void parseConfiguration(XNode root) { try { propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); // Java 数据类型和数据库数据类型转换器 typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
private void typeHandlerElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String typeHandlerPackage = child.getStringAttribute("name"); typeHandlerRegistry.register(typeHandlerPackage); } else { String javaTypeName = child.getStringAttribute("javaType"); String jdbcTypeName = child.getStringAttribute("jdbcType"); String handlerTypeName = child.getStringAttribute("handler"); Class<?> javaTypeClass = resolveClass(javaTypeName); JdbcType jdbcType = resolveJdbcType(jdbcTypeName); Class<?> typeHandlerClass = resolveClass(handlerTypeName); if (javaTypeClass != null) { if (jdbcType == null) { typeHandlerRegistry.register(javaTypeClass, typeHandlerClass); } else { typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass); } } else { typeHandlerRegistry.register(typeHandlerClass); } } } } } public abstract class BaseBuilder { protected final Configuration configuration; protected final TypeAliasRegistry typeAliasRegistry; protected final TypeHandlerRegistry typeHandlerRegistry; }
- SqlFactory 的核心功能就是提供创建 MyBatis 的核心接口 SqlSession. SqlSession 采用建造者模式进行构建:
- 构建映射器的内部组成:
MyBatis 中一条 SQL 和它相关的配置信息由: MappedStatement, SqlSource, BoundSql 3 个部分组成:- MappedStatement: 保存一个映射节点的内容, 也就是 mapper.xml 文件中的配置的相关信息. 它有一个重要的属性 sqlSource.
- SqlSource: 提供 BoundSql.
- BoundSql: 是 SqlSource 通过对 SQL 和参数的联合解析得到的 SQL 和参数. 它有 3 个常用的属性: sql, parameterObject, paramterMappings.
- parameterObject: 是描述 Mapper 接口中方法传递的参数. 当传递基本类型时, MyBatis 会将其转化为对应的包装类型; 当传递多个参数且没有使用 @Param 注解时, MyBatis 会把 parameterObject 变为一个 Map<String, Object> 对象, 如果使用 @Param 注解, 则会将 Map 的 key 设置 @Param 注解设置的名称;
/****未使用 @Param 注解*****/ // Mapper 接口方法定义 User selectByNameAndAddress(String name, String address); // 最终生成的 parameterObject Map<String, String> parameterObject = new HashMap<>(); parameterObject.put("arg0", "xiaoli"); parameterObject.put("param1", "xiaoli"); parameterObject.put("arg1", "beijing"); parameterObject.put("param2", "beijing"); /****使用 @Param 注解*****/ User selectByNameAndAddress(@Param("name")String name, @Param("address")String address); // 最终生成的 parameterObject Map<String, String> parameterObject = new HashMap<>(); parameterObject.put("name", "xiaoli"); parameterObject.put("param1", "xiaoli"); parameterObject.put("address", "beijing"); parameterObject.put("param2", "beijing");
- parameterMappings: 是一个 List, 它的每一个元素都是 ParameterMapping 对象. ParameterMapping 对象是描述 mapper.xml 中 SQL 语句定义的参数.
最终生成的 parameterMappings 就包括两个对象, 一个是 id 对应的 ParamterMapping 对象, 一个是 name 对应的 ParameterMapping 对象.<select id="selectByNameAndAddress" resultType="study.User"> SELECT id, name, address FROM user WHERE id = #{id} AND name = #{name} </select>
- sql: 是 mapper.xml 里面的一条被 SqlSource 解析后的 SQL.
- parameterObject: 是描述 Mapper 接口中方法传递的参数. 当传递基本类型时, MyBatis 会将其转化为对应的包装类型; 当传递多个参数且没有使用 @Param 注解时, MyBatis 会把 parameterObject 变为一个 Map<String, Object> 对象, 如果使用 @Param 注解, 则会将 Map 的 key 设置 @Param 注解设置的名称;
- SqlSession 运行过程:
首先生成 Mapper 接口的动态代理对象 MapperProxy 的实例, 当调用 Mapper 接口定义的方法时, 在 MapperProxy 实例里面将方法映射到 SqlSession#execute() 方法上执行, 最终再调用底层 Executor 的方法, 最终才调用 JDBC 的方法.// 调用 SqlSession#getMapper() 方法生成动态代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // SqlSession 实现 public class DefaultSqlSession implements SqlSession { @Override public <T> getMapper(Class<T> type) { // 这里将 SqlSession 当作参数传递进去 return configuration.<T>getMapper(type, this); } } // Configuration 实现 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { // mapperRegistry 是在构建 Configuration 时, 通过读取配置文件完成注册的 return mapperRegistry.getMapper(type, sqlSession); } // MapperRegistry 实现 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { // 通过代理工厂产生该 Mapper 接口的动态代理实例 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } // MapperProxyFactory 实现 protected T newInstance(MapperProxy<T> mapperProxy) { // 这里生成 Mapper 接口的代理对象 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } // MapperProxy 实现 public class MapperProxy<T> implements InvocationHandler, Serializable { // 调用任何一个 Mapper 接口的方法都会进入到这里 @Override 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); } final MapperMethod mapperMethod = cachedMapperMethod(method); // 这里调用 SqlSession 的 return mapperMethod.execute(sqlSession, args); } } // MapperMethod 实现 public Object execute(SqlSession sqlSession, Object[] args) { Object result; 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()) { // 这里调用了 executeForMany() 方法 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) { List<E> result; Object param = method.convertArgsToSqlCommandParam(args); if (method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); // 这里又调用了 sqlSession#selectList() 方法 result = sqlSession.<E>selectList(command.getName(), param, rowBounds); } else { result = sqlSession.<E>selectList(command.getName(), param); } if (!method.getReturnType().isAssignableFrom(result.getClass())) { if (method.getReturnType().isArray()) { return convertToArray(result); } else { return convertToDeclaredCollection(sqlSession.getConfiguration(), result); } } return result; } @Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); // 这里又调用 Executor#query() 方法 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(); } }
- SqlSession 下的四大对象:
- Executor: SqlSession 利用门面模式将 Executor 方法封装不同方法提供给客户端使用. Executor 是真正执行 Java 和数据库交互的对象. MyBatis 三种执行器:
- SIMPLE: 简易执行器, 默认的执行器
- REUSE: 能够执行重用预处理语句的执行器
- BATCH: 执行器重用语句和批量更新
执行器是在 Configuration 类当中生成的
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); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
- StatementHandler: 处理数据库会话. 数据库会话器也是在 Configuration 类当中生成的
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 这里生成的是 RoutingStatementHandler StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; } public class RoutingStatementHandler implements StatementHandler { private final StatementHandler delegate; public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } } } // Executor 中调用 StatementHandler private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); // 调用 StatementHandler#prepare() 方法, 做一些基础配置 stmt = handler.prepare(connection, transaction.getTimeout()); // 调用 StatementHandler#parameterize() 方法设置参数 handler.parameterize(stmt); return stmt; } // 在 StatementHandler 调用 ResultHandler 处理结果 @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { String sql = boundSql.getSql(); statement.execute(sql); // 调用 ResultHandler#handleResultSets() 方法 return resultSetHandler.<E>handleResultSets(statement); }
- ParameterHandler: 参数处理器, 对预编译语句进行参数设置
@Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters") .object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { // 这里根据 mapper.xml 配置的参数个数进行参数的设置 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 将 javaType 转换为 jdbcType typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
- ResultSet: 结果映射器, 将数据库查询结果组装为实体类.
@Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").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); }
- Executor: SqlSession 利用门面模式将 Executor 方法封装不同方法提供给客户端使用. Executor 是真正执行 Java 和数据库交互的对象. MyBatis 三种执行器:
- 参考:
[1] : Java EE互联网轻量级框架整合开发
来源:CSDN
作者:sparkchans
链接:https://blog.csdn.net/m0_37890535/article/details/103566586