ORM事务

2021/06/09 DB/JDBC/事务 共 3260 字,约 10 分钟
闷骚的程序员

1. 以mybatis作为案例,详细解释mybatis如何管理数据库事务

在使用 JDBC 手动管理事务的情况下,同一个事务中始终使用同一个数据库连接。原因是事务的操作(例如 commitrollback)是基于连接级别的,事务的边界由特定的连接来维护。

JDBC 手动事务管理的关键点

  1. 手动开启事务:
    Connection connection = dataSource.getConnection();
    connection.setAutoCommit(false); // 关闭自动提交,开始手动管理事务
    
  2. 在事务中操作: 只要是在同一个 Connection 对象上执行的操作(例如 prepareStatement 或其他查询操作),它们都属于这个事务的范围。
  3. 提交或回滚:
    connection.commit();  // 提交事务
    connection.rollback(); // 回滚事务
    

因此,在手动事务中,整个事务的操作是绑定到单一的 Connection 实例上的。


MyBatis 中的 SqlSessionConnection 的关系

在 MyBatis 中:

  • SqlSession 是一个核心对象,代表了与数据库交互的一次会话。
  • ConnectionSqlSession 用来执行实际数据库操作的底层对象。

关系分析:

  1. SqlSession 的生命周期
    • SqlSession 的生命周期通常对应于一个事务的生命周期。
    • 当通过 SqlSessionFactory 获取一个 SqlSession 时,MyBatis 会内部获取一个数据库连接并绑定到这个 SqlSession 中。
  2. 事务控制
    • 如果手动管理事务,MyBatis 不会自动关闭或提交 Connection,而是尊重用户在外部控制的事务范围。
    • 例如,如果手动设置了事务(setAutoCommit(false)),MyBatis 不会自动提交事务。
  3. 内部 Connection 的使用
    • SqlSession 内部通过 Transaction 对象来管理数据库连接。
    • 当调用 SqlSession 的操作方法(如 select, insert, update)时,MyBatis 会通过 Transaction 获取底层的 Connection,从而确保操作使用的是相同的连接。

示例:

// 手动事务控制
SqlSessionFactory sqlSessionFactory = ...; // 获取工厂
Connection connection = dataSource.getConnection();
connection.setAutoCommit(false);

try (SqlSession sqlSession = sqlSessionFactory.openSession(connection)) {
    // SqlSession 使用外部传入的 Connection
    MyMapper mapper = sqlSession.getMapper(MyMapper.class);
    mapper.insertData(...); // 使用同一个 Connection 执行操作

    connection.commit(); // 提交事务
} catch (Exception e) {
    connection.rollback(); // 回滚事务
    throw e;
} finally {
    connection.close(); // 关闭连接
}

结论

  1. 在 JDBC 手动事务中,整个事务使用的是同一个数据库连接。
  2. 在 MyBatis 中:
    • SqlSessionConnection 是关联的,SqlSession 使用底层的 Connection 执行操作。
    • 如果手动管理事务,可以将 Connection 显式传递给 SqlSession,MyBatis 会确保所有的数据库操作都在这个连接上进行,从而遵循事务的边界。

2. mybatis抽象一层SQLSession的目的

MyBatis 选择封装一层 SqlSession 来包装底层的 Connection,而不是直接暴露或使用 JDBC 的 Connection,是出于多方面的设计考虑。这种封装不仅简化了开发者的操作,还增强了框架的功能性和灵活性。以下是详细的原因和背后的设计理念:

1. 抽象化与简化操作

SqlSession 提供了一个更高层次的抽象,简化了数据库操作的复杂性。相比直接使用 ConnectionSqlSession 提供了更直观和易用的方法来执行 SQL 语句,例如 selectListinsertupdatedelete。这使得开发者无需关心底层 JDBC 的细节,如准备语句、设置参数和处理结果集。

2. 集成映射器(Mappers)

MyBatis 的核心功能之一是将 SQL 语句映射到 Java 方法。这通过 Mapper 接口和 XML 映射文件或注解实现。SqlSession 负责管理这些映射器,提供 getMapper 方法,使开发者能够通过接口调用数据库操作,而无需编写重复的 JDBC 代码。

try (SqlSession session = sqlSessionFactory.openSession()) {
    MyMapper mapper = session.getMapper(MyMapper.class);
    List<ResultType> results = mapper.selectSomething(params);
}

3. 事务管理

SqlSession 统一管理事务的开启、提交和回滚。通过 SqlSession,开发者可以更方便地控制事务的边界,而无需直接操作 Connection。这不仅减少了出错的可能性,还使得代码更加整洁和模块化。

try (SqlSession session = sqlSessionFactory.openSession()) {
    // 执行多个数据库操作
    session.insert(...);
    session.update(...);
    
    // 提交事务
    session.commit();
} catch (Exception e) {
    // 回滚事务
    session.rollback();
    throw e;
}

4. 资源管理

SqlSession 负责管理底层 Connection 的获取和释放,确保资源的正确关闭,避免连接泄漏。开发者只需关注 SqlSession 的生命周期,而不必手动管理 Connection

try (SqlSession session = sqlSessionFactory.openSession()) {
    // 使用 SqlSession 执行数据库操作
} // SqlSession 会自动关闭并释放连接

5. 缓存机制

SqlSession 集成了一级缓存(会话缓存),用于缓存同一会话中的查询结果,提升性能。通过封装 ConnectionSqlSession 能够更好地管理缓存的生命周期和策略,而无需开发者手动处理缓存逻辑。

6. 插件与扩展

MyBatis 支持插件机制,可以在 SqlSession 的操作过程中插入自定义逻辑(如日志记录、性能监控等)。这种封装使得扩展和定制变得更加灵活和方便。

7. 一致性与统一性

通过 SqlSession,MyBatis 提供了一个统一的接口来执行各种数据库操作,保持了一致的编程模型。无论是执行简单的 CRUD 操作,还是复杂的动态 SQL,开发者都可以通过 SqlSession 以一致的方式进行。

8. 抽象事务边界

SqlSession 抽象了事务的边界,使得事务管理与业务逻辑解耦。开发者可以通过 SqlSession 灵活地定义事务的范围,而不需要深入理解底层 Connection 的事务控制。

9. 集成其他功能

SqlSession 还集成了其他功能,如批量操作、动态 SQL、结果映射等。通过封装 ConnectionSqlSession 能够更好地协调这些功能的实现和应用。

总结

封装 SqlSession 而非直接使用 Connection,使 MyBatis 提供了一个功能丰富、易用且灵活的数据库操作接口。它不仅简化了开发过程,还增强了框架的可维护性和扩展性。通过 SqlSession,开发者能够更高效地进行数据库交互,同时享受到 MyBatis 提供的强大特性和便利。

文档信息

Search

    Table of Contents