本来不想写这个的,但是太容易忘记了,好不容易看了很久的源码才了解了一点,忘记可惜了。
Configuration:
a、 MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中
b、可以理解为所有mybatis文件的集合
DefaultSqlSessionFactory
在SqlSessionFactoryBuilder对象主要是为了获取SqlSessionFactory对象,在创建对象的过程来配置Configuration对象配置的实例的类就是DefaultSqlSessionFactory
DefaultSqlSessionFactory可以理解为工厂配置类
SqlSession:
作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能
从中获取会话的连接
Executor:
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
sql的执行器
StatementHandler:
封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等
ParameterHandler:
负责对用户传递的参数转换成JDBC Statement 所对应的数据类型
主要负责类型的转换
这个用户可以自己定制
ResultSetHandler:
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHandler
负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换
MappedStatement
MappedStatement维护一条<select|update|delete|insert>节点的封装
mapper文件中的一个id对应一个该对象
SqlSource
负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
BoundSql
表示动态生成的SQL语句以及相应的参数信息
MappedStatement
XML文件中的某个方法
StatementHandler
负责处理Mybatis与JDBC之间Statement的交互
RoutingStatementHandler
类似路由器,在其构造函数中会根据Mapper文件中设置的StatementType来选择使用
SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler,其实现的接口StatementHandler的方法也是由这三个具体实现类来实现。
Statement 对象用于将 SQL 语句发送到数据库中
SqlSessionFactory sessionFactory = null;
String resource = "mybatis.xml";
sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
SqlSession sqlSession = sessionFactory.openSession();
InitClass initClass = (InitClass) sqlSession.selectOne("com.example.demo.UserMapper.selectId");
System.out.println(initClass.getId());
我们已上面这段代码作为示例来进行说明
SqlSessionFactoryBuilder对象的作用就是用来生成SqlSessionFactory的。
Resources对象用来读取文件在项目中的路径,将之传入build方法中的会进入下面的步骤
public SqlSessionFactory build(Reader reader) {
// 主要引用下面的方法
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// XMLConfigBuilder 对象就是用来解析之前传入的xml文件的属性举例几个属性
//typeAliases设置别名 mappers 映射执行sql的xml文件
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
//parse()解析mybtis方法中configuration标签的下面的所有属性封装到Configuration对象
//build方法将解析完成的Configuration对象传入得到DefaultSqlSessionFactory类
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 Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
在通过build方法得到SqlSessionFactory对象后,后面肯定就是得到SqlSession类了继续执行openSession()
通过opSession方法真正执行的方法是openSessionFromDataSource()方法
// ExecutorType类 默认是simple类型
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// configuration为xml的配置类,getEnvironment方法可以得到数据库连接属性
final Environment environment = configuration.getEnvironment();
//得到事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//得到事务类型 其中getConnection方法是得到数据库连接
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//然后就是进入Executor 数据库的访问主要就是它来实现的(执行sql,返回对象,都是在这里完成)
final Executor executor = configuration.newExecutor(tx, execType);
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();
}
}
Exector:
Executor分成两大类,一类是CacheExecutor,另一类是普通BaseExecutor
CacheExecutor:加入的缓存功能这里就不多介绍了这里主要介绍BaseExecutor
newExecutor方法会是根据传入ExectorType类型选择一个Exector的实现类来完成SQL的执行方式
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
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);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
BaseExecutor中又分为一下类型
ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
ExecutorType.BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是 必须的,来保证一个简单并易于理解的行为。
这个类型是根据mybatis.xml中配置的没有配置的话默认SIMPLE
根据默认类型我们进入SimpleExecutor方法中
@Override
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:封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数,预编译语句,和基础的增删改查等
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
通过newStatementHandler方法来获得一个StatenenHandler对象
//RoutingStatementHandler类似路由器,在其构造函数中会根据Mapper文件中设置的StatementType来选择使用SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler,
其实现的接口StatementHandler的方法也是由这三个具体实现类来实现。
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// RoutingStatementHandler会根据类型选择具体的实现类来执行sql
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
通过MappedStatement储存的Statementype参数来确定具体执行SQL的处理者
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//默认是PreparedStatementHandler
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
在得到StatementHandler对象后 执行prepareStatement方法获取一个Statemen对象
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
//设置SQL的参数
handler.parameterize(stmt);
return stmt;
}
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
这里就用到了Transaction中的获取数据库连接
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
这里执行的就是具体在StatemenHandler中预编译方法的实现
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
最终指向的是默认PreparedStatementHandler对象中的方法来执行预编译语句返回一个Statemen对象
最后执行的handler.update(stmt)
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
指向就是PreparedStatementHandler类中的实现方法
接下来就是真正执行SQL的方法前面只是预编译语句
InitClass initClass = (InitClass) sqlSession.selectOne("com.example.demo.UserMapper.selectId");
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
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.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
接下来具体执行交给executor来执行,具体流程上面已经讲过了