MyBatis(六):SqlSession执行源码分析
针对以下代码
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
InputStream inputStream = null;
try {
//使用输入流读取文件
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
//现在我们分析这一行代码
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); }
该行代码:
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.实例化SqlSessionFactoryBuilde()对象。
2.执行build方法
-
实际上build方法有9个,这里只列出相关的2个。
//先走这里,实际是为了走下面的build方法,把enviroment和properties都给null
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
//真正要走的build方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//a.这一行其实不重要,就是通过几个构造器把InputStream换成了XMLConfigBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//b.通过XMLConfigBuilder.parse()对xml文件解析
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.
}
}
}
a.实例化XMLConfigBuilder
//a.实例化XMLConfigBuilder XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
a-1.XMLConfigBuilder构造器
//后面两个参数都是空,可以忽略,因此关键是new XPathParser(inputStream, true, props, new XMLMapperEntityResolver())
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
a-2. XPathParser构造器
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
//一般走的构造器properties是空的,但是如果给了properties,那么就会在这里赋值给configuration的属性properties
commonConstructor(validation, variables, entityResolver);
//在这里把InputStream类换成Document类
this.document = createDocument(new InputSource(inputStream));
}
b-1.通过XMLConfigBuilder.parse()对xml文件解析
//b.通过XMLConfigBuilder.parse()对xml文件解析 (parser.parse())
b-2.parse方法
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//parseConfiguration方法解析xml
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
b-3.parseConfiguration方法解析xml
//这个方法里就可以看到很多我们熟悉的设置了:properties,settings,typeAliases...
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
//properties设置,以这个为例
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
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);
}
}
b-4.propertiesElement(root.evalNode("properties"));
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//把xml文件<properties>中<property>的所有参数名、参数值以键值对放在defaults中
Properties defaults = context.getChildrenAsProperties();
//获取resource和url的参数值
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
//resource和url只能有1个
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.");
}
//把db.properties文件中的值放入到defaults中,注意上面是xml的properties配置,这里是文件
//因此properties文件是后覆盖的,优先级比xml文件要高
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
//查看configuration是否已经有属性了,如果有,就覆盖到defaults中
//这个实际上是build构造器中输入的属性值,在new SqlSessionFactoryBuilder().build(inputStream)方法中有输入的话,会在上文的a代码中写入到configuration类中。
//说明这里的构造器输入的优先级是最高的
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
//把default传入到configuration类中
configuration.setVariables(defaults);
}
}
b-5.返回到了最初的new SqlSessionFactoryBuilder().build(inputStream)方法的主线中
注意这时候我们走完的是parser.parser()
//b.通过XMLConfigBuilder.parse()对xml文件解析 return build(parser.parse());
实际上,接着要走的是build(configuration)
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
返回了 DefaultSqlSessionFactory的示例
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
InputStream inputStream = null;
try {
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
//现在SqlSessionFactory实例化成功了,注意这里其实是多态:
//类似:SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory();
//SqlSessionFactory是一个接口,被DefaultSqlSessionFactory继承
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//创建对象
public static SqlSession getSqlSession(){
//因此这个openSession方法实际上是被DefaultSqlSessionFactory重写的方法
return sqlSessionFactory.openSession();
}
}
3.DefaultSqlSessionFactory.openSession();
@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}
3-1.openSessionFromDataSource(execType, null, autoCommit);
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获取mybati-config.xml中配置的environment对象
final Environment environment = configuration.getEnvironment();
// 获取事务工厂对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 创建事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建Executor对象
final Executor executor = configuration.newExecutor(tx, execType);
// 创建DefaultSqlSession对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} 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也是多态,实际对象是DefaultSqlSession
-
事务和Executor在创建SqlSession以前就已经创建了
-
Executor的源码如下,简单浏览应该是执行sql的类。下次再继续查看
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean required) throws SQLException;
void rollback(boolean required) throws SQLException;
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
boolean isCached(MappedStatement ms, CacheKey key);
void clearLocalCache();
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
Transaction getTransaction();
void close(boolean forceRollback);
boolean isClosed();
void setExecutorWrapper(Executor executor);
}