1 概述
这两个类,SqlSessionFactory作为Mybatis的入口提供了各种获取SqlSession的函数。SqlSessionFactory大部分情况下生成唯一的实例,读写分离和多数据库除外。SqlSession主要用于提供CRUD操作。
2 SqlSessionFactory
我们来看一下SqlSessionFactory的源码。
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();
}
通过上面的源码我们可以发现SqlSessionFactory的作用主要是通过是否自动提交、事务的隔离级别、数据库连接或者执行器类型等来创建SqlSession的。
在这里针对器其现类,我们仅仅看一下DefaultSqlSessionFactory,因为另一个实现类SqlSessionManager官方已经不建议使用了,这里我也就不深入分析了。
当然根据抽象工厂函数设计模式的作用我们可以猜想这个DefaultSqlSessionFactory的作用是用于创建DefaultSqlSession的。
查看DefaultSqlSessionFactory的源码实现,可以看见DefaultSqlSessionFactory对SqlSessionFactory中的函数的实现都是依赖于openSessionFromDataSource和openSessionFromConnection函数的。
(1)openSessionFromDataSource函数
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);
//初始化执行器(Mapper文件的sql语句都是通过其执行的)
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();
}
}
(2)openSessionFromConnection函数
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
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();
}
}
上面两个方法的区别就在于生成事务对象的时候传入的参数不同,一个是依赖于DataSource对象,一个是依赖于Connection对象。如果是openSessionFromDataSource,我们可以看见,最终在调用openConnection函数创建连接的时候依然会通过dataSource来获取到Connection。
@Override
public Connection getConnection() throws SQLException {
//如果Connection不能存在则通过DataSource创建Connection
if (connection == null) {
openConnection();
}
return connection;
}
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
}
3 SqlSession
这个是使用Mybatis的接口,通过这个接口我们可以执行SQL命令、管理事务和获取到Mapper对象。
针对这个类的数据库CRUD方法我们仅仅看看两个基本的方法就行,因为其余的方法都是基于这两个方法执行的。
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
//获取到Mapper文件的sql语句块封装对象
MappedStatement ms = configuration.getMappedStatement(statement);
//最终调用Executor的query函数,针对Executor的分析我们前面已经提到
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
//获取到Mapper文件的sql语句块封装对象
MappedStatement ms = configuration.getMappedStatement(statement);
//最终调用Executor的update函数,针对Executor的分析我们前面已经提到
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
上面就是对SqlSessionFactory和SqlSession的分析,下面我们将使用一篇文章来分析Mybatis中SQL执行的整个过程。欢迎交流。