MyBatis的Sql执行过程源码解读
来源:互联网 发布:卫生部 疾病数据 编辑:程序博客网 时间:2024/04/20 21:23
1.先获得SqlSessionFactory
通过SqlSessionFactoryBuilder去读取mybatis的配置文件,然后build一个DefaultSqlSessionFactory。
/** * 一系列的构造方法最终都会调用本方法(配置文件为Reader时会调用本方法,还有一个InputStream方法与此对应) * @param reader * @param environment * @param properties * @return */ public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { //通过XMLConfigBuilder解析配置文件,解析的配置相关信息都会封装为一个Configuration对象 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); //这儿创建DefaultSessionFactory对象 return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { //通过Configuration对象去获取相关的配置信息,Environment对象包含了数据源和事务的配置 final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //实际上就是Executor来执行sql语句,executor是对于Statement的封装 final Executor executor = configuration.newExecutor(tx, execType, autoCommit); //创建DefaultSqlSession对象 return new DefaultSqlSession(configuration, executor); } 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(); } }这样就获得了SqlSession对象
3.通过SqlSession获得Mapper
public <T> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); }这里通过Configuration的getMapper方法来获得
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
继续看MapperRegistry的getMapper方法
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 { return mapperProxyFactory.newInstance(sqlSession); //此处使用反射,生成一个MapperProxyFactory对象 } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);"> </span>
knownMappers在读取配置文件的时候,已经将mapper信息放入其中了。
继续看MapperProxyFactory的newInstance方法:
protected T newInstance(MapperProxy<T> mapperProxy) { 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就是一个代理类,使用的是jdk的动态代理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }这里的invoke方法可以明确看出使用的是jdk的动态代理
这样的话就会返回一个mapper的代理类,每次执行的时候,回交给MapperMethod类的execute方法
public Object execute(SqlSession sqlSession, Object[] args) { Object result; if (SqlCommandType.INSERT == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); } else if (SqlCommandType.UPDATE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else if (SqlCommandType.DELETE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else if (SqlCommandType.SELECT == command.getType()) { 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 { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } } else { 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;}可以看出,也就是判断一下CURD的类型,然后实际调用的还是SqlSession 的方法,在这里以selectList为例
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); return result; } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }继续查找Executor的query方法,在这里使用BaseExecutor的
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }继续查找到SimpleExecutor的doQuery,可以看到
public <E> List<E> 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(this, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); stmt = handler.prepare(connection); handler.parameterize(stmt); return stmt; }可以看出实际上也就好似调用的jdbc
0 0
- MyBatis的Sql执行过程源码解读
- mybatis源码学习之执行过程分析(5)——sql执行后ResultSet的处理及结果返回
- jQuery源码解读---执行过程分析
- mybatis源码学习之执行过程分析(4)——映射文件中sql的获取和sql语句的执行
- Zeus源码解读之定时任务执行与手动执行任务的过程分析
- MyBatis源码分析-SQL语句执行的完整流程
- MyBatis源码分析-SQL语句执行的完整流程
- mybatis源码分析,sql语句执行的完整流程
- 解读sql的执行计划!
- MyBatis执行动态sql及存储过程
- Mybatis中SQL语句执行过程详解
- Mybatis 源码 sql执行流程分析
- MyBatis的执行过程总结
- mybatis--源码解读---XML的解析
- mybatis系列(四)--mybatis的核心:sql的执行流程(深入源码)
- Arduino IDE的编译执行过程解读
- Python程序执行过程的整合解读
- Arduino IDE的编译执行过程解读
- CentOS----kdump failed
- Activity传递返回参数+生命周期+横竖屏+保持临时数据
- Delphi开发IE中添加工具栏
- wampserver2.5 发布后不能访问 you don't have permission to access
- 类似百度搜索输入keyword进行找到含keyword相关内容
- MyBatis的Sql执行过程源码解读
- 使用mybatis时可能出现的问题
- linux 文本处理一
- 从一个简单的小实例分析JSP+Servelt与JSP+Struts2框架的区别
- NYOJ 58--最少步数【DFS】
- 面对无秘,假设你是微信的产品经理浅析
- 选项菜单+上下文菜单+子菜单
- mysql 存储过程复制A表数据到B表
- ASP.NET弹出窗口,返回值