Honeyc's Blog

mybatis-配置加载-源码分析

一、Mybaits基础

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手工设置参数以及抽取结果集。MyBatis 使用简单的 XML 或注解来配置和映射基本体,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

1.MyBatis的框架架构

czx_life

API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。   

2.原理详解:

MyBatis应用程序根据XML配置文件创建SqlSessionFactory,SqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSession。SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。

二、 Mybaits源码结构

源代码主要在org.apache.ibatis目录下,18个包,其中在应用中主要的包有:builder、session、cache、type、transaction、datasource、jdbc、mapping,提供支撑服务的包有annotation、binding、io、logging、plugin、reflection、scripting、exception、executor、parsing.
czx_life
1.注解
org.apache.ibatis.annotations
2.绑定
org.apache.ibatis.binding
3.构建
org.apache.ibatis.builder
org.apache.ibatis.builder.annotation
org.apache.ibatis.builder.xml
4.缓存
org.apache.ibatis.cache
org.apache.ibatis.cache.decorators
org.apache.ibatis.cache.impl
5.数据源
org.apache.ibatis.datasource
org.apache.ibatis.datasource.jndi
org.apache.ibatis.datasource.pooled
org.apache.ibatis.datasource.unpooled
6.异常
org.apache.ibatis.exceptions
7.执行器
org.apache.ibatis.executor
org.apache.ibatis.executor.keygen
org.apache.ibatis.executor.loader
org.apache.ibatis.executor.loader.cglib
org.apache.ibatis.executor.loader.javassist
org.apache.ibatis.executor.parameter
org.apache.ibatis.executor.result
org.apache.ibatis.executor.resultset
org.apache.ibatis.executor.statement
8.IO
org.apache.ibatis.io
通过类加载器在jar包中寻找一个package下满足条件(比如某个接口的子类)的所有类
9.jdbc单元测试工具
org.apache.ibatis.jdbc
10.日志
org.apache.ibatis.logging
org.apache.ibatis.logging.commons
org.apache.ibatis.logging.jdbc
org.apache.ibatis.logging.jdk14
org.apache.ibatis.logging.log4j
org.apache.ibatis.logging.log4j2
org.apache.ibatis.logging.nologging
org.apache.ibatis.logging.slf4j
org.apache.ibatis.logging.stdout
11.映射
org.apache.ibatis.mapping
12.解析
org.apache.ibatis.parsing
xml解析,${} 格式的字符串解析
13.插件
org.apache.ibatis.plugin
14.反射
org.apache.ibatis.reflection
org.apache.ibatis.reflection.factory
org.apache.ibatis.reflection.invoker
org.apache.ibatis.reflection.property
org.apache.ibatis.reflection.wrapper
15.脚本
org.apache.ibatis.scripting
org.apache.ibatis.scripting.defaults
org.apache.ibatis.scripting.xmltags
16.会话
org.apache.ibatis.session
org.apache.ibatis.session.defaults
17.事务
org.apache.ibatis.transaction
org.apache.ibatis.transaction.jdbc
org.apache.ibatis.transaction.managed
18.类型处理器
org.apache.ibatis.type
实现java和jdbc中的类型之间转换 

整体框架理解:

初始化Mybatis,所有的配置都在Configuration对象中使用Mybatis,从SqlSessionFactory工厂中获取SqlSession,从Configuration对象中获取mapper对象,并返回结果Mybatis在加载mapper的时候对mapper接口的注解进行解析重要的几个包:io、session、builder、mapper(annotations、binding)、executor。

MyBatis sqlSession的产生过程

(1)、SqlSessionFactoryBuilder:build方法创建SqlSessionFactory实例。是用过即丢,其生命周期只存在于方法体内。
(2)、SqlSessionFactory:openSession创建SqlSession实例的工厂。单例,存在于整合应用运行时。
(3)、SqlSession:用于执行持久化操作的对象,类似于jdbc中的Connection。
1
2
3
4
5
6
7
8
9
10
11
12
// 通过对sqlSession的创建的例子,对源码的进行解读:
public static SqlSession getSqlSession() {
SqlSession session = null;
try {
InputStream stream = Resources.getResourceAsStream("sqlMapper.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(stream);
session = factory.openSession();
} catch (Exception e) {
e.printStackTrace();
}
return session;
}

(1)SqlSessionFactoryBuilder:支持9种构造方法,其实最主要的是包含Configuration对象的构造方法,目的是为了通过加载配置文件创造SqlSessionFactory对象,真实最终返回的是DefaultSqlSessionFactory对象:

czx_life

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package org.apache.ibatis.session;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
/**
* Builder是一种设计模式(建造者模式),一般用于创建复杂对象
* 这里重载了9个build方法,为了提供尽可能多的方式来灵活的生成SqlSessionFactory的实例
* ,SqlSessionFactory本身不复杂*,复杂的其内部的Configuration对象
* 解析配置的过程都交给个XMLConfigBuilder,然后最终实例化是 {@link #build(Configuration)} 来完成的
*/
public class SqlSessionFactoryBuilder {
//以下3个方法都是调用下面第4种方法
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
/* 第4种方法是最常用的,它使用了一个参照了XML文档或更特定的SqlMapConfig.xml文件的Reader实例。
可选的参数是environment和properties。Environment决定加载哪种环境(开发环境/生产环境),包括数据源和事务管理器。
如果使用properties,那么就会加载那些properties(属性配置文件),
那些属性可以用${propName}语法形式多次用在配置文件中。
和Spring很像,一个思想。
*/
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//委托XMLConfigBuilder来解析xml文件,并构建
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
//这里是捕获异常,包装成自己的异常并抛出的idiom?,最后还要reset ErrorContext
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
//以下3个方法都是调用下面第8种方法
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
/**
* InputStream读取配置的最终入口
*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
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.
}
}
}
/**
* 创建了默认的SqlSessionFactory实现类
* @param config {@link Configuration}实例
* @return SqlSessionFactory的实现类:{@link DefaultSqlSessionFactory}
*/
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}

从中我们看到了有一段很核心的代码,下面那段,这应该是去解析XML配置文件去了,解析完得出了一个Configuration对象,可以先猜测下这个Configuration对象和我们配置文件都是一一对应的:

1
2
3
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//此处返回的是Configuration对象
return build(parser.parse());

再看看Configuration对象的一些核心属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
package org.apache.ibatis.session;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.builder.CacheRefResolver;
import org.apache.ibatis.builder.ResultMapResolver;
import org.apache.ibatis.builder.annotation.MethodResolver;
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.decorators.FifoCache;
import org.apache.ibatis.cache.decorators.LruCache;
import org.apache.ibatis.cache.decorators.SoftCache;
import org.apache.ibatis.cache.decorators.WeakCache;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import org.apache.ibatis.executor.BatchExecutor;
import org.apache.ibatis.executor.CachingExecutor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ReuseExecutor;
import org.apache.ibatis.executor.SimpleExecutor;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.loader.ProxyFactory;
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.InterceptorChain;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.LanguageDriverRegistry;
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeAliasRegistry;
import org.apache.ibatis.type.TypeHandlerRegistry;
/**
* 配置类
*/
public class Configuration {
/**
* 一个environment就是一个数据源,在多个数据源的项目中,可以配置多个environment元素,然后指定不同的ID
* 在测试、开发、上线不同的环境中,可以方便的切换environment
*/
protected Environment environment;
/** 是否允许在嵌套语句中使用分页(RowBounds)。一般是不建议使用mybatis的分页的
* 因为它还是查询了所有的结果集,在内存中进行计算和分页,并不是在database端进行的物理分页
* 如果数据量较大,会造成数据库和网络压力
*/
protected boolean safeResultHandlerEnabled = true;
protected boolean safeRowBoundsEnabled = false;
/* 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
*/
protected boolean mapUnderscoreToCamelCase = false;
/** 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载。
*/
protected boolean aggressiveLazyLoading = true;
/**
*是否允许单一语句返回多结果集(需要兼容驱动)。
*/
protected boolean multipleResultSetsEnabled = true;
/**
* 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。
*/
protected boolean useGeneratedKeys = false;
/**
* 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。
*/
protected boolean useColumnLabel = true;
/**
* 是否使用缓存,该配置影响的所有映射器中配置的缓存的全局开关
*/
protected boolean cacheEnabled = true;
/**
* 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。
*/
protected boolean callSettersOnNulls = false;
/**
* Mybatis的日志前缀
*/
protected String logPrefix;
/**
* 指定 MyBatis 所用日志的具体实现,未指定时将自动查找
* SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
* 默认值:空
*/
protected Class <? extends Log> logImpl;
protected Class<? extends VFS> vfsImpl;
/**
*Mybatis的本地缓存,默认的级别是session级的,这个缓存可以防止循环引用和加速重复的查询工作
* SESSION级的会缓存一个会话中所执行的所有查询
* STATEMENT级缓存,对同一个SqlSession的不同调用将不会共享数据
* {@link LocalCacheScope}
*/
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
/**
* 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
*/
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
/**
* 懒加载被触发的方法
*/
protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
protected Integer defaultStatementTimeout;
/**
* 设置超时时间,它决定驱动等待数据库响应的秒数。
*/
protected Integer defaultStatementTimeout;
/**
* 默认的SQL执行器是SIMPLE的,具体可以详见{@link SimpleExecutor}
*/
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
/**
* 指定 MyBatis 应如何自动映射列到字段或属性。
* NONE 表示取消自动映射;
* PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。
* FULL 会自动映射任意复杂的结果集(无论是否嵌套)
*/
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
protected Properties variables = new Properties();
protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
protected ObjectFactory objectFactory = new DefaultObjectFactory();
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
/**
* 延迟加载的开关,在开启时,所有的关联对象都会被延迟加载。
* 在特定的关联关系中,可以通过指定fetchType来覆盖懒加载的状态
*/
protected boolean lazyLoadingEnabled = false;
/**
* 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。
*/
protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
protected String databaseId;
protected Class<?> configurationFactory;
/**
* 拦截器链(参考责任链chain设计模式)
*/
protected final InterceptorChain interceptorChain = new InterceptorChain();
//类型处理器注册机 数据库类型 <==> Java类型 的相互转换的处理
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
//类型别名注册机
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
//映射的语句,存在Map里
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
//缓存,存在Map里
protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
//结果映射,存在Map里
protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");
protected final Set<String> loadedResources = new HashSet<String>();
protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");
//不完整的SQL语句
protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();
/**
* 映射保存缓存引用关系。 关键是引用绑定到另一个命名空间的缓存的命名空间,
* 该值是实际缓存绑定到的命名空间。
*/
protected final Map<String, String> cacheRefMap = new HashMap<String, String>();
***
****
*****
******

(2)、返回的DefaultSqlSessionFactory​ ,可进行Sqlsession的创建,Sqlsession对应着一次数据库会话。由于数据库回话不是永久的,因此Sqlsession的生命周期也不应该是永久的,相反,在你每次访问数据库时都需要创建它(当然并不是说在Sqlsession里只能执行一次sql,你可以执行多次,当一旦关闭了Sqlsession就需要重新创建它)。创建Sqlsession的地方只有一个,那就是SqlsessionFactory的openSession方法。

czx_life
SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package org.apache.ibatis.session;
import java.sql.Connection;
/**
* 构建SqlSession的工厂.工厂模式
*/
public interface SqlSessionFactory {
//8个方法可以用来创建SqlSession实例
SqlSession openSession();
//自动提交
SqlSession openSession(boolean autoCommit);
//连接
SqlSession openSession(Connection connection);
//事务隔离级别
SqlSession openSession(TransactionIsolationLevel level);
//执行器的类型
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
DefaultSqlSessionFactory实现SqlsessionFactory。对sqlSession进行创建
package org.apache.ibatis.session.defaults;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
/**
* 默认的SqlSessionFactory
*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
//最终都会调用2种方法:openSessionFromDataSource,openSessionFromConnection
//以下6个方法都会调用openSessionFromDataSource
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
@Override
public SqlSession openSession(ExecutorType execType) {
return openSessionFromDataSource(execType, null, false);
}
@Override
public SqlSession openSession(TransactionIsolationLevel level) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return openSessionFromDataSource(execType, level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}
//以下2个方法都会调用openSessionFromConnection
@Override
public SqlSession openSession(Connection connection) {
return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
}
@Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return openSessionFromConnection(execType, connection);
}
@Override
public Configuration getConfiguration() {
return configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//通过事务工厂来产生一个事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//生成一个执行器(事务包含在执行器里)
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();
}
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
//如果没有配置事务工厂,则返回托管事务工厂
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
private void closeTransaction(Transaction tx) {
if (tx != null) {
try {
tx.close();
} catch (SQLException ignore) {
// Intentionally ignore. Prefer previous error.
}
}
}
}

从DefaultSessionFactory中的private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {}方法可以看出,创建sqlsession经过了以下几个主要步骤:

1) 从配置中获取Environment;
2) 从Environment中取得DataSource;
3) 从Environment中取得TransactionFactory;
4) 从DataSource里获取数据库连接对象Connection;
5) 在取得的数据库连接上创建事务对象Transaction;
6) 创建Executor对象(该对象非常重要,事实上sqlsession的所有操作都是通过它完成的);
7) 创建sqlsession对象。

时序图:
czx_life
设计模式:
工厂模式SqlSessionFactory
建造模式SqlSessionFactoryBuilder
单例模式LogFactory
装饰模式Cache:采用装饰模式,一个个包装起来,形成一个链,典型的就是SynchronizedCache->LoggingCache->SerializedCache->LruCache->PerpetualCache,通过链起来达到功能增加
(1)、 SynchronizedCache 同步缓存,防止多线程问题。核心: 加读写锁,
ReadWriteLock.readLock().lock()/unlock()
ReadWriteLock.writeLock().lock()/unlock()
(2)、LoggingCache 日志缓存,添加功能:取缓存时打印命中率
(3)、SerializedCache 序列化缓存 用途是先将对象序列化成2进制,再缓存
(4)、LruCache 最近最少使用缓存,核心就是覆盖 LinkedHashMap.removeEldestEntry方法,返回true或false告诉 LinkedHashMap要不要删除此最老键值。LinkedHashMap内部其实就是每次访问或者插入一个元素都会把元素放到链表末尾,这样不经常访问的键值肯定就在链表开头啦。
(5)、PerpetualCache 永久缓存,一旦存入就一直保持,内部就是一个HashMap,所有方法基本就是直接调用HashMap的方法
(6)、FifoCache 先进先出缓存,内部就是一个链表,将链表开头元素(最老)移除
(7)、ScheduledCache 定时调度缓存, 目的是每一小时清空一下缓存
(8)、SoftCache 软引用缓存,核心是SoftReference
(9)、 WeakCache 弱引用缓存,核心是WeakReference
(10)、TransactionalCache 事务缓存,一次性存入多个缓存,移除多个缓存
czx_life