MyBatis-05-MyBatis使用流程简读
代码
// 使用流程
// 1. 读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 2. 创建 SqlSessionFactory 工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 生产 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 获取 代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
// 5. 执行方法
List<User> users = userDao.findAll();
System.out.println(Arrays.toString(users.toArray()));
// 6. 释放资源
sqlSession.close();
inputStream.close();
new SqlSessionFactoryBuilder().build
new SqlSessionFactoryBuilder: 没有做额外动作,只是新建了一个实例,说明它不是线程安全的,每次使用要新建一个
build: 解析 XML,并将生成的相关配置保存到 Configuration 实例中,并且使用这个 Configuration 作为构造函数参数构建 DefaultSqlSessionFactory 实例
DefaultSqlSessionFactory
SqlSessionFactory: SqlSession 的实例工厂
- 获取 MyBatis 配置对象 Configuration
- 可配置
- 自动提交
- 连接对象
- 事务隔离级别
- 执行器类型
两个实现类: DefaultSqlSessionFactory、SqlSessionManager
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();
}
DefaultSqlSessionFactory
- 不传是否自动提交,默认不自动提交
- 不传事务隔离级别,默认使用数据库的事务隔离级别
- 不传执行器类型,默认使用 Configuration 的配置(默认是 SIMPLE)
- 保存了 Configuration 实例
下面仅列出得到 SqlSession 的方法
openSessionFromConnection: 通过数据库连接创建对象的 SqlSession 对象
Connection -> new Transaction -> new Executor -> new DefaultSqlSession,Transaction & Executor & DefaultSqlSession 一一对应
// 从 Connection 获取 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;
}
// Environment 保存了对应 XML 标签的内容,即数据库连接相关配置
final Environment environment = configuration.getEnvironment();
// 主要是做了如果没有配置就使用 ManagedTransactionFactory, 因为是直接使用数据库连接获取的, Managed 本身又是数据库相关由外部控制的,因此可直接 new 它而不需要其他配置
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 事务管理: 封装 Connection 的提交回滚等操作
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();
}
}
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);
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();
}
}
SqlSession
- getMapper 获得 Dao/Mapper 直接操作
- 其它的一般都是 MyBatis 自己调用的接口,Dao/Mapper 的操作实际底层也是委托到他们去调用,说白了 Dao/Mapper 是持有对应 SqlSession 实例的
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
// 其他 selectOne 略
<E> List<E> selectList(String statement);
<T> Cursor<T> selectCursor(String statement);
void select(String statement, Object parameter, ResultHandler handler);
// 其他略
// insert、update、delete
void commit();
void rollback();
Configuration getConfiguration();
// 获取 Dao/Mapper
<T> T getMapper(Class<T> type);
// 获取数据库连接对象
Connection getConnection();
}
构造函数
// 持有配置对象,执行器对象
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);
}
selectOne/selectList
其他也差不多,基本上都是委托给 executor 执行的
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
// statement: 类名 + 方法名, 就是 XML 中一个方法的 id
// parameter: =MapperMethod.ParamMap,方法参数
// rowBounds: 分页参数
// handler: 返回值处理
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();
}
}
getMapper
Configuration 有 mapperRegistry 实例,所有 Mapper 都需要注册到 mapperRegistry 才能使用
Mapper 绑定 SqlSession,每次 getMapper 都是一个新的 Mapper 实例,不是单例
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
public <T> T Configuration.getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
public <T> T MapperRegistry.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);
}
}
Mapper 实例都是代理,持有 SqlSession,于是可以直接通过 SqlSession 执行 SQL
public T MapperProxyFactory.newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}