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 的实例工厂

  1. 获取 MyBatis 配置对象 Configuration
  2. 可配置
  • 自动提交
  • 连接对象
  • 事务隔离级别
  • 执行器类型

两个实现类: 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

  1. 不传是否自动提交,默认不自动提交
  2. 不传事务隔离级别,默认使用数据库的事务隔离级别
  3. 不传执行器类型,默认使用 Configuration 的配置(默认是 SIMPLE)
  4. 保存了 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

  1. getMapper 获得 Dao/Mapper 直接操作
  2. 其它的一般都是 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);
}
posted @ 2024-04-16 22:43  YangDanMua  阅读(10)  评论(0编辑  收藏  举报