1.SqlSessionFactory
SqlSessionFactory是MyBatis的关键对象。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得,而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。每一个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心。同时SqlSessionFactory也是线程安全的,SqlSessionFactory一旦被创建,应该在应用执行期间都存在。在应用运行期间不要重复创建多次,建议使用单例模式。SqlSessionFactory是创建SqlSession的工厂。
SqlSessionFactory的接口如下,主要作用是创建SqlSession对象
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创建SqlSessionFactory
SqlSessionFactory是由SqlSessionFactoryBuilder创建。
2.SqlSession
SqlSession是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection。它是应用程序与持久层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操作的关键对象。SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接。可以用SqlSession实例来直接执行被映射的SQL语句。每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,同时SqlSession也是线程不安全的。使用完SqlSeesion之后关闭Session很重要,应该确保使用finally块来关闭它。
2.1创建SqlSession
SqlSession对象是由SqlSessionFactory对象创建。主要代码如下:
// 从数据源获取connection 进而获取SqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// autoCommit 设置从Transaction获取的connection是否可以 自动提交
// Transaction封装了数据库连接connection的获取、释放、关闭、提交、回滚
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 把Transaction封装进Executor里面执行增删改查。
final Executor executor = configuration.newExecutor(tx, execType);
// Executor封装进SqlSession。作为门面来执行一系列操作
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对象之后就可以利用SqlSession内部的方法进行CRUD操作了。
与数据库打交道必不可少的是JDBC Connection。Transaction对象就是封装了数据源与Connection。可以从连接池中获取连接,使用后关闭连接,把连接回归连接池中,实现connection的复用。不用重复新建连接。可以参考PooledDataSource代码
2.2 sqlSession的功能
- 主要API:增、删、改、查
- 辅助API:提交、关闭会话、事务回滚、清除缓存、批量操作时刷新Statements
这些功能都依赖于Executor执行器来实现
主要方法如下:
2.2.1 查询
- 直接返回列表
@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();
}
}
- 把结果封装进传入的ResultHandler中,会在查询结果集映射的时候使用。
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
public class DefaultResultHandler implements ResultHandler<Object> {
private final List<Object> list;
public DefaultResultHandler() {
list = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public DefaultResultHandler(ObjectFactory objectFactory) {
list = objectFactory.create(List.class);
}
@Override
public void handleResult(ResultContext<?> context) {
list.add(context.getResultObject());
}
public List<Object> getResultList() {
return list;
}
}
2.2.2 更新(增、删、改)
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();
}
}
xception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}