在 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();
}
}
在这种情况下,userMapper
和 orderMapper
使用的是同一个 SqlSession
。
总结:
- 如果使用 Spring 和事务管理,那么在同一个方法中调用多个 MyBatis Mapper 方法时,会在同一个
SqlSession
中执行。 - 如果手动管理
SqlSession
,则可以选择在一个或多个SqlSession
中执行,具体取决于你如何创建和使用SqlSession
。