mybatis 学习四 源码分析 mybatis如何执行的一条sql
总体三部分,创建sessionfactory,创建session,执行sql获取结果
1,创建sessionfactory
//mybatis配置文件
String resource = "conf.xml";
InputStream is = TestMybatis.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
1,xml转换成Configuration对象
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//environment表示要使用哪个db,properties 表示资源信息
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
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.
}
}
}
//将xml中的所有节点都解析成对象信息
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//获取xml里面设置的
Properties defaults = context.getChildrenAsProperties();
//获取指定的资源文件里的
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
//覆盖掉了xml里配置的
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
//覆盖掉了上面的
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
//如果没有指定,那么直接使用默认的
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
//获取事物factory
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//获取datasourcefactory
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
//根据type来决定要实例化哪个factory出来
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
//根据type来决定实例化哪个factory
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
最重要的是mappers的转换,这里的方法就把所有的sql语句就转换过来了,将来要找的话,也是这里的源泉。
2,将这个转换好的configuration对象组装成一个DefaultSqlSessionFactory,就可以供外部使用了。
//返回sessionfactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
2,创建sqlsession
1,首先从confinguration对象中,找到对应的事物factory,这里有两种facroty。
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
//这里就是直接使用的jdbc的提交
connection.commit();
}
}
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
//这里就是直接使用的jdbc的回滚
connection.rollback(); } }
//提交和回滚什么都不做,让别人来管理
public void commit() throws SQLException {
// Does nothing
} public void rollback() throws SQLException {
// Does nothing
}
2,然后从configuration中获取到对应的datasource,这里就可能有三种了
private Connection doGetConnection(Properties properties) throws SQLException {
//初始化驱动
initializeDriver();
//jdbc直接获取一个连接
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);
return connection;
}
//方法内容过多,可以自己去看 这里是从一个集合中pop出来一个连接直接使用。
private PooledConnection popConnection(String username, String password) throws SQLException {
//从jndi上下文中直接获取数据源并返回
if (properties.containsKey(INITIAL_CONTEXT)
&& properties.containsKey(DATA_SOURCE)) {
Context ctx = (Context) initCtx.lookup(properties.getProperty(INITIAL_CONTEXT));
dataSource = (DataSource) ctx.lookup(properties.getProperty(DATA_SOURCE));
} else if (properties.containsKey(DATA_SOURCE)) {
dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE));
}
3,将得到的datasource和事物facroty一起用来,获取一个tx。
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
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, autoCommit);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
4,得到这个执行器之后,组装成sqlsession然后返回供外部使用。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//得到db信息
final Environment environment = configuration.getEnvironment();
//得到事物factory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//根据数据源得到事物
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//得到执行器
final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
//执行器和配置信息对象一起组装了session返回。
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();
}
}
3,执行sql查询。
1,首先会根据sql的id去configuration对象中找到对应的sql,返回的是一个 MappedStatement,这里面有所有这个sql的信息,
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//根据id找到对应的sql的封装对象 statement
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();
}
}
2,执行执行器的查询方法,如果二级缓存开启了那么会使用CachingExecutor的query,这里会先去这个MappedStatement里的缓存里找,如果找不到,在去执行sql,
public <E> List<E> 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, parameterObject, boundSql);
if (!dirty) {
cache.getReadWriteLock().readLock().lock();
try {
//这里从二级缓存中找一下
@SuppressWarnings("unchecked")
List<E> cachedList = (List<E>) cache.getObject(key);
if (cachedList != null) return cachedList;
} finally {
cache.getReadWriteLock().readLock().unlock();
}
}
//执行sql查询
List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
return list;
}
}
return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
3,二级缓存里如果找不到
//一级缓存查找
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//sqldb查找
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
mybatis 学习四 源码分析 mybatis如何执行的一条sql的更多相关文章
- 【转】MaBatis学习---源码分析MyBatis缓存原理
[原文]https://www.toutiao.com/i6594029178964673027/ 源码分析MyBatis缓存原理 1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 ...
- DotNetty网络通信框架学习之源码分析
DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...
- Yii2 源码分析 入口文件执行流程
Yii2 源码分析 入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...
- 精尽MyBatis源码分析 - MyBatis初始化(四)之 SQL 初始化(下)
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽 MyBatis 源码分析 - MyBatis 初始化(一)之加载 mybatis-config.xml
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - MyBatis初始化(二)之加载Mapper接口与XML映射文件
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽 MyBatis 源码分析 - MyBatis 初始化(三)之 SQL 初始化(上)
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - MyBatis 的 SQL 执行过程(一)之 Executor
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis源码分析-MyBatis初始化流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
随机推荐
- 解决ajax get方式提交中文参数乱码问题
最近在工作中遇到,使用ajax get方式提交中文参数的时候出现乱码,通过上网搜索,总结出比较简单的两种解决方案: 第一种,由于tomcat默认的字符集是ISO-8859-1,修改Tomcat中的se ...
- HDU - 1176 免费馅饼 【DP】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1176 思路 因为刚开始的起点是固定的 但是终点不是固定的 所以我们可以从终点往起点推 dp[i][j] ...
- curl 监控web
[root@rhel6 ~]# curl -I -s -w "%{http_code}\n" -o /dev/null http://127.0.0.1 [root@rhel6 ~ ...
- springmvc的优化
二.springmvc的工作机制 在容器初始化时会建立所有url和controller的对应关系,保存到Map<url,controller>中.tomcat启动时会通知spring初始化 ...
- Javascript 模块化编程 --RequireJs
什么是模块化 模块就是实现特定功能的一组方法,常见的几种js写法 原始写法 function A() { } function B() { } 上面函数A()和B()组成一个模块,使用的时候直接调用就 ...
- 关于from..import 与import导入模块问题
问题来源:导入PyQt5里面的模块时老是出错 1.from PyQt5 import QtWidgets.QApplication,QtWidgets.QtDialog #出错2.from PyQt5 ...
- IpIImage -> CvMat 转换方法
Ipl转为CvMat 一般为这两种方法: 1: /*cvGetMat*/ CvMat matheader; CvMat * mat = cvGetMat(img, &matheader); 2 ...
- codeforces 710C C. Magic Odd Square(构造)
题目链接: C. Magic Odd Square Find an n × n matrix with different numbers from 1 to n2, so the sum in ea ...
- WampServer 2.5设置外网访问/局域网手机访问(403 Forbidden错误解决方法)
安装好wamp后,想用手机通过局域访问电脑上wamp下的网页,结果出现如下提示. (403 Forbidden)错误 1.打开http.conf文件 2.找到下图中红色方框中的onlineofflin ...
- Android: 一个两点触控的案例
下面是一个两点触控的案例代码: package com.zzj; import android.app.Activity; import android.os.Bundle; import andro ...