在 MyBatis 中,一级缓存和二级缓存是用于提升查询效率的两种缓存机制,主要通过减少对数据库的访问来提高性能。

1. 一级缓存 (Local Cache)

一级缓存是SqlSession 级别的缓存,它的生命周期与 SqlSession 一致。MyBatis 默认开启一级缓存,且每个 SqlSession 都有自己独立的缓存区域。

  • 缓存范围:一级缓存的作用范围是 SqlSession。也就是说,同一个 SqlSession 内的查询操作,如果执行了相同的 SQL 语句且参数相同,MyBatis 会从缓存中直接获取结果,而不再查询数据库。
  • 失效条件
  • SqlSession 被关闭、提交、回滚后,一级缓存将失效。
  • 执行了任何增删改操作,缓存将被清空。
  • 查询操作涉及不同的参数或 SQL 语句,一级缓存不会命中。

一级缓存适用于短期的数据库操作,由于它的作用范围仅限于当前 SqlSession,因此其生命周期较短。

2. 二级缓存 (Global Cache)

二级缓存是Mapper 级别的缓存,它的生命周期相对较长,作用范围是整个应用程序中共享的。同一个 Mapper 对应的二级缓存数据,可以在不同 SqlSession 中共享。

  • 缓存范围:二级缓存的作用范围是 Mapper(即每个映射文件有自己独立的缓存)。多个 SqlSession 共享同一个 Mapper 时,如果前一个 SqlSession 执行了查询,结果会被存入二级缓存中,之后的 SqlSession 可以从缓存中读取,而不需要再查询数据库。
  • 失效条件
  • 执行了增删改操作,会使相关的缓存失效。
  • 配置文件中没有开启二级缓存(默认关闭)。
  • 必须显式地在 Mapper 中配置 <cache /> 或者使用注解 @CacheNamespace 才能启用二级缓存。

二级缓存适用于更大范围的数据共享,但由于缓存生命周期较长,可能导致缓存不一致问题。因此,需要合理配置缓存策略。

两者的区别:

  • 范围不同:一级缓存是 SqlSession 级别的,二级缓存是 Mapper 级别的。
  • 生命周期:一级缓存的生命周期与 SqlSession 一致,而二级缓存的生命周期与整个应用程序一致,直到缓存失效。
  • 共享范围:一级缓存不在 SqlSession 之间共享,而二级缓存可以在不同 SqlSession 之间共享。

在 MyBatis 中,是否在一个方法中调用多个接口方法时会使用同一个 SqlSession,取决于具体的 SqlSession 管理方式。通常有两种常见的方式来管理 SqlSession

1. 使用 Spring 管理 MyBatis (@MapperScan 和 Spring 事务管理器)

如果你使用 Spring 框架来管理 MyBatis 的 SqlSession,并且启用了 Spring 的事务管理(如使用 @Transactional 注解),那么在同一个方法中调用多个 MyBatis 接口方法时,所有这些操作会共享同一个 SqlSession,并且在同一个事务中执行。

  • 事务控制:Spring 的事务管理器会在事务开始时创建一个 SqlSession,并将该 SqlSession 绑定到当前线程。因此,只要在同一个事务上下文中(即在同一个 @Transactional 注解的方法内),调用的所有 MyBatis Mapper 方法都会共享这个 SqlSession
  • 一级缓存共享:由于所有的数据库操作都使用同一个 SqlSession,它们会共享同一个一级缓存。
@Service
public class MyService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Transactional
    public void process() {
        userMapper.updateUser(...);   // 使用同一个 SqlSession
        orderMapper.createOrder(...); // 使用同一个 SqlSession
    }
}

在这种情况下,userMapper.updateUser()orderMapper.createOrder() 都会使用同一个 SqlSession,并在同一个事务中提交或回滚。

2. 手动管理 SqlSession

如果没有使用 Spring 的事务管理,而是手动管理 SqlSession,比如通过 SqlSessionFactory.openSession() 手动创建 SqlSession,那么在同一个方法中,你可以选择在一个或多个 SqlSession 中执行操作。

  • 一个 SqlSession:如果在方法中只创建一个 SqlSession 并使用它调用多个 Mapper 方法,那么这些操作都会在同一个 SqlSession 中执行。
  • 多个 SqlSession:如果在方法中每次都通过 SqlSessionFactory 创建新的 SqlSession,那么每个操作都会在不同的 SqlSession 中执行。
public void process() {
    SqlSession session = sqlSessionFactory.openSession();
    try {
        UserMapper userMapper = session.getMapper(UserMapper.class);
        OrderMapper orderMapper = session.getMapper(OrderMapper.class);
        
        userMapper.updateUser(...);   // 使用同一个 SqlSession
        orderMapper.createOrder(...); // 使用同一个 SqlSession
        
        session.commit();  // 在一个事务中提交
    } finally {
        session.close();
    }
}

在这种情况下,userMapperorderMapper 使用的是同一个 SqlSession

总结:

  • 如果使用 Spring 和事务管理,那么在同一个方法中调用多个 MyBatis Mapper 方法时,会在同一个 SqlSession 中执行。
  • 如果手动管理 SqlSession,则可以选择在一个或多个 SqlSession 中执行,具体取决于你如何创建和使用 SqlSession