1. SqlSessionFactory
SqlSessionFactory 接口从名字就可以看出其为 SqlSession 对象工厂中的核心接口,其中除了一个获取当前工厂所使用的 Configuration 配置类的 getConfiguration 方法以外,全都是通过指定条件获取 SqlSession 对象的 openSession 方法。
public interface SqlSessionFactory {
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();
}
1.1 SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 类为 SqlSessionFactory 工厂的构造器类,它主要功能就是构建 SqlSessionFactory 工厂;其提供了三组不同的建造方法,一种是使用 xml 配置文件的字符流进行建造,第二种则是使用字节流进行建造,最后一种则是直接利用 Configuration 配置文件对象构建 DefaultSqlSessionFactory 默认 SqlSession 工厂;
不管是使用字符流还是字节流构造的逻辑都是首先创建 XMLConfigBuilder 对象,然后调用其 parse 方法(Mybatis源码学习(一)——配置文件加载)将 Xml 配置文件解析为 Configuration 对象,最后使用 Configuration 对象直接创建默认 SqlSession 工厂 DefaultSqlSessionFactory 对象。
public class SqlSessionFactoryBuilder {
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);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
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);
}
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 {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
1.2 DefaultSqlSessionFactory
DefaultSqlSessionFactory 为 mybatis 中默认使用的 SqlSession 对象工厂类,其只有一个 configuration 配置对象属性 ,只有一个构造器,因此在创建 DefaultSqlSessionFactory 必须传入要使用的 configuration 配置对象;
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
}
通过对 DefaultSqlSessionFactory 实现的 openSession 方法进行观察,首先可以发现可以使用多个参数组合创建 SqlSession,其中 execType 在没传的情况下默认使用全局默认配置的执行器类型、autoCommit 自动提交默认为关闭的;同时发现底层通过 openSessionFromDataSource 与 openSessionFromConnection 方法构建 SqlSession,其中 openSessionFromConnection 使用数据库连接对象进行构建,其他情况则使用 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);
}
@Override
public SqlSession openSession(Connection connection) {
return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
}
@Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return openSessionFromConnection(execType, connection);
}
openSessionFromConnection 与 openSessionFromDataSource 方法首先都是利用数据库设置调用 getTransactionFactoryFromEnvironment 方法生成事务工厂同时利用事务工厂创建事务对象,然后利用传入的执行器类型与生成的事务对象使用 configuration 的 newExecutor 方法生成执行器,最后利用利用配置对象、执行器以及是否自动提交创建 SqlSession;
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 createSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
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);
return createSqlSession(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();
}
}
根据 getTransactionFactoryFromEnvironment 方法可以看出如果配置了事务工厂时直接获取设置的事务工厂,未设置事务工厂时则是使用 ManagedTransactionFactory ;
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
从 createSqlSession 方法看出 DefaultSqlSessionFactory 中最终生成 DefaultSqlSession 。
protected SqlSession createSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
return new DefaultSqlSession(configuration, executor, autoCommit);
}
2. SqlSession 接口
sqlSession 接口为 mybatis 核心接口,所有增删改查都是通过该接口中方法执行的,除增删改查之外还提供获取关联配置文件对象的 getConfiguration 方法、获取关联链接的 getConnection 方法、清除缓存的 clearCache 方法以及根据对象类型对象生成特定对象的 getMapper 方法。因此如果 mybatis 提供的 sqlSession 实现类无法满足需求,比如说分库分表、数据管理及自定义缓存时都可以通过自定义实现 sqlSession 接口来实现,mybatis 原生实现 sqlSession 接口的类只有 SqlSessionManager 与 DefaultSqlSession;
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
<K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
<T> Cursor<T> selectCursor(String statement);
<T> Cursor<T> selectCursor(String statement, Object parameter);
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);
void commit();
void commit(boolean force);
void rollback();
void rollback(boolean force);
List<BatchResult> flushStatements();
@Override
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> type);
Connection getConnection();
}
2.1 DefaultSqlSession
DefaultSqlSession 作为 mybatis 与数据库交互的核心类,首先我们关注他的属性字段,其拥有配置 configuration、执行器 executor、是否自动提交 autoCommit、dirty 以及当前正在使用的指针列表 cursorList,其中 configuration、executor 与 autoCommit 都是使用 final 进行修饰,只会在对象构建之初进行赋值,其中 configuration 与 executor 都是必传,autoCommit 默认 false,dirty 属性初始化为 false。
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
}
2.1.1 mapper 接口实现方法解析
getMapper 方法用于实现指定接口,其直接调用 configuration 对象中的 getMapper 方法,随后调用 mapperRegistry 属性的 getMapper 方法实现 mapper 接口;
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
public class Configuration {
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
}
mapperRegistry 中的 getMapper 方法首先从 knownMappers 中获取 MapperProxyFactory 接口代理工厂对象,MapperProxyFactory 对象是在之前解析 mapper 文件或接口时添加的;然后调用 MapperProxyFactory 的 newInstance 方法创建代理对象;
public class MapperRegistry {
private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new ConcurrentHashMap<>();
public MapperRegistry(Configuration config) {
this.config = config;
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
}
MapperProxyFactory 为接口代理工厂,其中 mapperInterface 属性为当前代理工厂代理的接口类型对象,methodCache 为代理接口的方法实现缓存,newInstance 方法通过调用 java 的动态代理对象 Proxy 生成指定接口的动态代理对象,其对接口方法的具体实现则是在 MapperProxy 方法中。
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethodInvoker> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
2.1.2 查询方法解析
sqlSession 中有 4 组不同的查询方法,即查询单个结果集的 selectOne 方法、使用指定字段对结果集进行标识的 selectMap 方法、获取指定结果集指针的 selectCursor 方法、查询多个结果集的 selectList 方法以及不返回结果直接使用 ResultHandler 对处理结果集的 select 方法;
selectOne 方法较为简单,其实就是直接调用 selectList 方法将所有满足条件的结果全查询出来,然后判断结果集大小是否为 1,为 1 是直接返回,大于 1 时直接抛出异常,未查询到结果时直接返回 null;
public class DefaultSqlSession implements SqlSession {
@Override
public <T> T selectOne(String statement) {
return this.selectOne(statement, null);
}
@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);
}
if (list.size() > 1) {
throw new TooManyResultsException(
"Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
}
selectMap 方法则是首先调用 selectList 方法查出所有满足条件的结果集,然后创建并利用 mapResultHandler 对象中的 handleResult 将结果集按照指定属性值与结果键值对组合的形式返回给调用方;
public class DefaultSqlSession implements SqlSession {
@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
final List<? extends V> list = selectList(statement, parameter, rowBounds);
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
final DefaultResultContext<V> context = new DefaultResultContext<>();
for (V o : list) {
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
return mapResultHandler.getMappedResults();
}
}
select 方法其实就是利用传入的 ResultHandler 对象来处理结果集,而获取最终的查询结果集的一种方法;
public class DefaultSqlSession implements SqlSession {
@Override
public void select(String statement, Object parameter, ResultHandler handler) {
select(statement, parameter, RowBounds.DEFAULT, handler);
}
@Override
public void select(String statement, ResultHandler handler) {
select(statement, null, RowBounds.DEFAULT, handler);
}
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
selectList(statement, parameter, rowBounds, handler);
}
}
selectList 方法调用的是 executor 中的 query 方法对数据库进行查询,注意在该方法中会利用 MappedStatement 对象的 dirtySelect 属性更新 dirty 属性值;
public class DefaultSqlSession implements SqlSession {
@Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, 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) {
return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
dirty |= ms.isDirtySelect();
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
selectCursor 方法目的为获取指定结果集的指针,其实际使用 executor 属性的 queryCursor 方法获取到指定结果集的指针;同时为了方便后续对指针进行同一的管理,会调用 registerCursor 方法将获取到的指针保存到 cursorList 之中;最后该方法与 selectList 方法一样,在查询时也会利用 MappedStatement 对象的 dirtySelect 属性更新 dirty 属性值;
public class DefaultSqlSession implements SqlSession {
@Override
public <T> Cursor<T> selectCursor(String statement) {
return selectCursor(statement, null);
}
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter) {
return selectCursor(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
dirty |= ms.isDirtySelect();
Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
registerCursor(cursor);
return cursor;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private <T> void registerCursor(Cursor<T> cursor) {
if (cursorList == null) {
cursorList = new ArrayList<>();
}
cursorList.add(cursor);
}
}
2.1.3 增删改方法解析
增删改方法对于 SqlSession 对象而言,实际上只有一个 update 更新方法,update 方法底层则是调用 executor 对象的 update 方法,在调用 update 方法之前首先将 dirty 属性置为真;
public class DefaultSqlSession implements SqlSession {
@Override
public int insert(String statement) {
return insert(statement, null);
}
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public int update(String statement) {
return update(statement, null);
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public int delete(String statement) {
return update(statement, null);
}
@Override
public int delete(String statement, Object parameter) {
return update(statement, parameter);
}
}
2.1.3 事务方法
事务管理方法主要有三个:commit 用于提交食物、rollback 用于回滚事务以及 close 用于关闭事务;
与其他方法一样,事务相关的方法底层也是通过调用 executor 中的相关方法实现对事务的管理的,在对事务进行操作之后,将 dirty 初始化为 false;其中 isCommitOrRollbackRequired 方法为标识是否需要对事务强行进行操作;
public class DefaultSqlSession implements SqlSession {
@Override
public void commit() {
commit(false);
}
@Override
public void commit(boolean force) {
try {
executor.commit(isCommitOrRollbackRequired(force));
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public void rollback() {
rollback(false);
}
@Override
public void rollback(boolean force) {
try {
executor.rollback(isCommitOrRollbackRequired(force));
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error rolling back transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));
closeCursors();
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
private void closeCursors() {
if (cursorList != null && !cursorList.isEmpty()) {
for (Cursor<?> cursor : cursorList) {
try {
cursor.close();
} catch (IOException e) {
throw ExceptionFactory.wrapException("Error closing cursor. Cause: " + e, e);
}
}
cursorList.clear();
}
}
}
private boolean isCommitOrRollbackRequired(boolean force) {
return !autoCommit && dirty || force;
}
}
对于 close 关闭事务方法来说,除了调用 executor 中的 close 方法关闭事务之外,还会调用 closeCursors 方法关闭当前还在使用的所有指针对象;