目录
简介
MyBatis是一个支持半自动化的持久层框架,它提供了缓存机制来优化数据库访问性能。MyBatis的缓存机制可以分为一级缓存和二级缓存两个层次。
一级缓存(本地缓存):
一级缓存是默认开启的,它是在SqlSession级别的缓存,即同一个SqlSession对象中,对于相同的查询语句,首次查询会将查询结果缓存起来,后续再次执行相同的查询语句时,会直接从缓存中获取结果,而不再发送SQL到数据库。
一级缓存是基于对象引用的缓存,因此当SqlSession进行增删改操作时,会清空该SqlSession的一级缓存,保证缓存数据与数据库的一致性。
一级缓存的生命周期与SqlSession的生命周期一致,即当SqlSession关闭后,一级缓存也会被清空。
二级缓存(全局缓存):
二级缓存是跨SqlSession的缓存,可以被多个SqlSession共享。
二级缓存需要手动配置开启,在映射文件中的<cache>元素进行配置。
当查询语句命中二级缓存时,会直接从缓存中获取结果,而不会再次发送SQL到数据库。
二级缓存是基于序列化的方式实现的,因此缓存的对象需要实现Serializable接口。
二级缓存的生命周期与整个应用的生命周期一致,在应用关闭前,缓存中的数据会一直存在。
两个缓存失效的场景
下面我们通过代码来详细讲解 MyBatis 的缓存机制,并举例两个缓存失效的场景:
- 更新操作导致缓存失效
- 手动清除缓存
我们使用 MyBatis 来配置和执行 SQL 查询,并观察缓存的效果。首先是 MyBatis 的 XML 映射文件 UserMapper.xml
,定义了 User
对象的 SQL 映射。
<!-- UserMapper.xml -->
<mapper namespace="com.example.UserMapper">
<select id="getUserById" resultType="com.example.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper
然后是对应的 Java 接口 UserMapper.java
,定义了查询用户信息的方法。
// UserMapper.java
import com.example.User;
public interface UserMapper {
User getUserById(int id);
}
接着,我们编写测试代码来演示缓存失效的两种情况:
import com.example.User;
import com.example.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
public class Main {
public static void main(String[] args) throws IOException {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询,会发送实际的 SQL 查询请求
User user1 = userMapper.getUserById(1);
System.out.println(user1);
// 第二次查询,会从本地缓存中获取,不会发送实际的 SQL 查询请求
User user2 = userMapper.getUserById(1);
System.out.println(user2);
// 更新操作导致缓存失效
User newUser = new User();
newUser.setId(1);
newUser.setName("Updated Name");
userMapper.updateUser(newUser);
sqlSession.commit();
// 更新操作导致缓存失效,再次查询会发送实际的 SQL 查询请求
User user3 = userMapper.getUserById(1);
System.out.println(user3);
// 手动清除缓存
sqlSession.clearCache();
// 手动清除缓存,再次查询会发送实际的 SQL 查询请求
User user4 = userMapper.getUserById(1);
System.out.println(user4);
sqlSession.close();
}
}
在这个示例中,我们首先创建了一个
SqlSessionFactory
实例,并使用它来打开一个SqlSession
。然后,我们获取了UserMapper
接口的实现,执行了两次查询操作,观察到了本地缓存的效果。接着,我们模拟了两种缓存失效的情况:
- 更新操作导致缓存失效:当执行更新操作后,之前缓存的查询结果会失效,需要重新查询数据库。
- 手动清除缓存:通过手动调用
sqlSession.clearCache()
方法,可以清除本地缓存,导致之后的查询重新发送 SQL 查询请求。通过这个示例,我们详细讲解了 MyBatis 的缓存机制,并演示了两种缓存失效的情况。