架构设计

- API层
提供给外部使用的接口API,开发人员通过这些本地API来操控数据库
与数据库交互有两种方式:使用传统的MyBatis提供的API;使用Mapper代理; - 数据处理层
负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理。它主要的目的是根据调用的请求完成一次数据库操作 - 基础支撑层
负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件,为上层的数据处理层提供最基础的支撑
主要构件及其相互关系
- SqlSession
作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能 - Executor
MyBatis执行器,是MyBatis调度的核心,负责SQL语句的生成和查询缓存的维护 - StatementHandler
封装了JDBC Statement操作,负责对JDBC statement的操作,如设置参数、将statement结果集转换成List集合 - ParameterHandler
负责对用户传递的参数转换成JDBC statement所需要的参数 - ResultSetHandler
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合 - TypeHandler
负责Java数据类型和jdbc数据类型之间的映射和转换 - MappedStatement
MappedStatement维护了一条<select|update|delete|insert>节点的封装 - SqlSource
负责根据用户传递的parameterObject动态地生成SQL语句,将信息封装到BoundSql对象中,并返回 - BoundSql
表示动态生成的SQL语句以及相应的参数信息 - Configuration
MyBatis所有的配置信息都维持在Configuration对象之中

传统方式源码剖析
初始化
InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSessionFactory构建器将数据流交给XMLConfigBuilder来解析,并将解析出来的数据存储在Configuration对象中,最后利用Configuration构建出SqlSessionFactory对象
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// XMLConfigBuilder是专门解析MyBatis的配置文件的类
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// parser.parse()返回值是Configuration对象
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.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
XmlConfig构建器从数据流中解析出properties、settings、typAliases、typeHandlers、objectFactory、mappers等数据,存储在Configuration实例中
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
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);
// 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);
}
}
执行SQL流程
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("com.hooda.test.dao.UserMapper.selectList");
SqlSession
SqlSession是一个接口,有两个实现类:DefaultSqlSession和SqlSessionManager(弃用)
SqlSession是MyBatis中用于和数据库交互的顶层类,通常将它和ThreadLocal绑定,一个会话使用一个SqlSession并且在使用完后需要close
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
}
SqlSession中有两个最重要的参数,Configuration与初始化相同,Executor为执行器
Executor
Executor也是一个接口,有三个常用的实现类:
BatchExecutor:重用语句并执行批量更新
ReuseExector:重用预处理语句preparedStatement
SimpleExecutor:普通执行器
获取SqlSession
public SqlSession openSession() {
// Configuration中 defaultExecutorType = ExecutorType.SIMPLE;
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
// ExecutorType 为Executor的类型
// TransactionIsolationLevel为事务隔离级别
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);
// 根据参数创建指定类型的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中的API
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 根据传入的全限定名+方法名从映射map中取出MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
// 调用Executor中的方法处理
// RowBounds是用来逻辑分页
// wrapCollection(parameter)是用来装饰集合或者数组参数
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();
}
}
Executor源码
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler) throws SQLException {
// 根据传入的参数动态获取SQL语句,最后返回用BoundSql对象表示
BoundSql boundSql = ms.getBoundSql(parameter);
// 本次查询创建缓存key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 如果缓存中没有本次查找的值,那么从数据库中查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 查询方法
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
// 将查询结果放入缓存
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
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对象来执行查询
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter,
rowBounds, resultHandler, boundSql);
// 创建JDBC中的Statement对象
stmt = prepareStatement(handler, ms.getStatementLog());
// StatementHandler进行处理
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 代码中的getConnection方法经过重重调用最后会调用openConnection方法,从连接池中获得链接
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
// 从连接池中获取链接
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
Executor的功能和作用
1> 根据传递的参数完成SQL语句的动态解析,生成BoundSql对象,共StatementHandler使用
2> 为查询创建缓存,以提高性能
3> 创建JDBC的Statement连接对象,传递给StatementHandler对象,返回List查询结果
StatementHandler源码
// 调用preparedStatement.execute方法,然后将ResultSet交给ResultSetHandler处理
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
// 使用ParameterHandler对象来完成对Statement的设值
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
StatementHandler主要工作
1、对于JDBC的PreparedStatement类型的对象,创建过程中,我们使用的是SQL语句字符串会包含若干个?占位符,我们其后再对占位符进行设值。StatementHandler通过parameter(statement)方法对Statement进行设值
2、StatementHandler通过query方法来完成Statement和将Statement对象返回的ResultSet封装
ParameterHandler源码
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
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)) { // issue #448 ask first for additional params
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);
}
// 每一个Mapping都有一个TypeHandler,根据TypeHandler来对preparedStatement进行设置参数
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 设置参数
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);
}
}
}
}
}
ResultSetHandler源码
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
// 多ResultSet的结果集合,每个ResultSet对应一个Object对象。实际上,每个Object是List<Object>对象
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
// 获取首个ResultSet对象,并封装成ResultSetWrapper对象
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 在不考虑存储过程的多ResultSet的情况,普通的查询实际上就一个ResultSet,也就是说ResultMaps就一个元素
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
// 获得ResultMap对象
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理ResultSet,将结果添加到MultipleResults中
handleResultSet(rsw, resultMap, multipleResults, null);
// 获得下一个ResultSet对象,并封装成ResultSetWrapper对象
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++;
}
}
// 如果是MultipleResults单元素,则取首元素返回
return collapseSingleResultList(multipleResults);
}
网友评论