带你学习Mybatis之SqlSession



SqlSession是mybatis的核心接口,SqlSessionFactory负责创建SqlSession对象,包含多个openSession()方法的重载。
在SqlSession中定义了常用的数据库操作以及事务操作,接口定义如下

SqlSession

public interface SqlSession extends Closeable {
	// 参数为sql语句,返回查询的结果对象
  <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);

	// 查询结果对象将由此指定的ResultHandler对象处理
  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();

	// 关闭当前session
  @Override
  void close();

	// 清空缓存
  void clearCache();

	// 获取Configuration对象
  Configuration getConfiguration();

	// 获取type对应的Mapper对象
  <T> T getMapper(Class<T> type);

	// 获取该SqlSession对应的数据库连接
  Connection getConnection();
}

MyBatis为SqlSession提供了默认实现,DefaultSqlSession类

	// Configuration配置对象
  private final Configuration configuration;
  	// 底层依赖的Executor对象
  private final Executor executor;
	// 是否自动提交事务
  private final boolean autoCommit;
  	// 当前缓存中是否存在脏数据
  private boolean dirty;
  	// 防止用户忘记关闭已打开的游标,cursorList收集由该SqlSession对象生成的游标对象,在DefaultSqlSession.close()方法统一关闭
  private List<Cursor<?>> cursorList;

所有的数据库相关操作全部封装到了Executor接口实现中,DefaultSqlSession类中查询方法的调用关系如下图

方法调用关系
查询最终都是调用Executor.query(MappedStatement, Object, RowBounds, ResultHandler)方法实现数据库查询操作的。

对返回对象进行调整

  • selectOne()方法从结果集中获取第一个元素返回
  • selectMap()方法将List集合转为Map集合返回
  • select()方法将结果对象集合交由用户指定的ResultHandler对象处理,且没有返回值
  • selectList()方法直接将集合返回

DefaultSqlSession中的insert()、update()、delete()方法最后通过调用DefaultSqlSession.update(String,Object)方法,从而调用Executor.update(MappedStatement, Object)方法完成数据库的修改操作。

DefaultSqlSessionFactory

DefaultSqlSessionFactory实现了SqlSessionFactory接口,提供了两种创建DefaultSqlSession的方式

方式一

通过数据源获取数据库连接,并创建Executor对象以及DefaultSqlSession对象

// ExecutorType是一个枚举
// SIMPLE, 为每个语句的执行创建一个新的预处理语句
// REUSE, 复用预处理语句
// BATCH 批量执行所有更新语句
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 获取mybatis-config.xml的配置中的Environment对象
      final Environment environment = configuration.getEnvironment();
      // 获取TransactionFactory
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 创建Transaction
      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();
    }
  }
方式二

用户提供数据库连接,根据数据库连接创建Executor对象以及DefaultSqlSession对象

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 new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
SqlSessionManager

SqlSessionManager同时实现了SqlSessionFactory和SqlSession接口,也提供了SqlSessionFactory创建SqlSession对象以及SqlSession操作数据库的功能。

private final SqlSessionFactory sqlSessionFactory;
// localSqlSession中记录的sqlSession对象的代理对象,SqlSessionManager初始化时会使用JDK动态代理的方式创建
private final SqlSession sqlSessionProxy;
// 记录当前一个与当前线程绑定的SqlSession对象
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal();

SqlSessionManager与DefaultSqlSessionFactory主要不同点是SqlSessionManager提供了两种模式:第一种模式和DefaultSqlSessionFactory的行为相同,同一个线程每次通过SqlSessionManager对象访问数据库时,都会创建新的DefaultSession对象完成数据库操作

第二种模式是SqlSessionManager通过localSqlSession这个ThreadLocal变量,记录当前线程绑定的SqlSession对象,供当前线程循环使用,从而避免在同一个线程多次创建SqlSession对象带来的性能损失

// 通过构造函数可以看出,sqlSessionProxy是代理类,会执行SqlSessionManager.SqlSessionInterceptor中的方法
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionManager.SqlSessionInterceptor());
}
private class SqlSessionInterceptor implements InvocationHandler {
    public SqlSessionInterceptor() {
        // Prevent Synthetic Access
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      // 会使用第二种模式
      if (sqlSession != null) {
        try {
          return method.invoke(sqlSession, args);
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
      } else {// 第一种模式
        try (SqlSession autoSqlSession = openSession()) {
          try {
            final Object result = method.invoke(autoSqlSession, args);
            autoSqlSession.commit();
            return result;
          } catch (Throwable t) {
            autoSqlSession.rollback();
            throw ExceptionUtil.unwrapThrowable(t);
          }
        }
      }
    }
  }
四大对象

sqlSession真正的执行时通过Executor、StatementHandler、ParameterHandler、ResultSetHandler来完成数据库操作和结果返回

  • Executor 执行器 通过执行器来调度StatementHandler、ParameterHandler和ResultHandler等来执行对应的sql
  • StatementHandler 使用数据库的Statement/PreparedStatement执行操作
  • ParameterHandler 用于sql对参数的处理
  • ResultSetHandler 进行结果集ResultSet的封装和返回

参考文献

MyBatis使用SqlSession来执行数据库操作。SqlSessionMyBatis的核心接口,它提供了多种方法来执行SQL语句、提交事务、获取映射器等操作。 首先,你需要通过SqlSessionFactory来创建SqlSession对象。SqlSessionFactory是由MyBatis配置文件和映射文件构建而成的,它负责创建SqlSession对象。 下面是使用SqlSessionFactory创建SqlSession的代码示例: ```java String resource = "mybatis-config.xml"; // MyBatis配置文件的路径 InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); ``` 一旦你获得了SqlSession对象,你就可以使用它来执行各种数据库操作。以下是一些常用的SqlSession方法: - `selectOne(String statement, Object parameter)`:查询单条记录。 - `selectList(String statement, Object parameter)`:查询多条记录。 - `insert(String statement, Object parameter)`:插入数据。 - `update(String statement, Object parameter)`:更新数据。 - `delete(String statement, Object parameter)`:删除数据。 - `commit()`:提交事务。 - `rollback()`:回滚事务。 其,`statement`参数是映射文件定义的SQL语句的唯一标识,`parameter`参数是传递给SQL语句的参数。 使用完SqlSession后,记得关闭它以释放资源: ```java sqlSession.close(); ``` 这就是MyBatis使用SqlSession进行数据库操作的基本流程。希望能对你有所帮助!如果还有其他问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拾光师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值