文章目录
一、Mybatis中的缓存
什么是缓存?
存在于内存中的临时数据。
为什么使用缓存?
减少和数据库的交互次数,提高执行效率、
什么样的数据能使用缓存,什么样的数据不能使用缓存
适用于缓存:
经常查询,并且不经常改变的。
数据的正确与否对最终结果影响不大的。
不适用于缓存的:
例如:商品的库存,银行的汇率,股市的牌价。
二、Mybatis中的一级缓存和二级缓存
一级缓存
1、说明:
它指的是Mybatis中的SQLSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。
该区域的结构是一个map,当我们再次查询同样的数据,mybatis会先去SQLSession中
查询是否有,有的话直接拿出来使用。
当SQLSession对象消失时,mybatis的一级缓存就消失了。
2、注意:
一级缓存是sqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()等
方法时,就会清空一级缓存。
二级缓存
1、说明:
它指的是Mybatis中SQLSessionFactory对象的缓存。由同一个SQLSessionFactory对象创建的SqlSession
共享其缓存。
2、二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(SQLMapConfig.xml中配置)
<!-- 配置参数 -->
<settings>
<!-- 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 -->
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<!-- 开启user支持二级缓存 -->
<cache></cache>
第三步:让当前的操作支持二级缓存(在select标签中配置)
<!-- 根据id查询 -->
<select id="findById" parameterType="INT" resultType="User" useCache="true">
select * from user where id=#{id}
</select>
测试代码
第一步:创建一个SqlSessionFactory对象
第二步:创建两个SqlSession对象
思想:如图。
代码:
factory= new SqlSessionFactoryBuilder().build(in);
@Test
public void testFirstCache() {
//第一个SqlSession对象
SqlSession sqlSession1 = factory.openSession(true);
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = userDao1.findById(41);
System.out.println(user1);
sqlSession1.close();//一级缓存消失
//第二个SqlSession对象
SqlSession sqlSession2 = factory.openSession(true);
IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = userDao2.findById(41);
System.out.println(user2);
System.out.println(user1==user2);
System.out.println(user1==user2);
}
三、一级缓存
分析: 一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等
public class MybatisTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession sqlSession;
private IUserDao userDao;
@Before
public void init() throws IOException {
//1、读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory工厂(工厂模式)
factory= new SqlSessionFactoryBuilder().build(in);
//3、使用工厂生产SqlSesson对象
sqlSession = factory.openSession(true);//手动将事务提交方式改为自动提交
//4、使用SqlSession创建Dao接口的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destory() throws Exception {
//提交事务
//sqlSession.commit();
//6、释放资源
sqlSession.close();
in.close();
}
/**
* 测试一级缓存
*/
@Test
public void testFirstCache() {
User user1 = userDao.findById(41);
System.out.println(user1);//com.song.domain.User@18ce0030
User user2 = userDao.findById(41);
System.out.println(user2);//com.song.domain.User@18ce0030
System.out.println(user1==user2);//true
}
/**
* 测试一级缓存
* 一下三种方式都可以清空缓存
*/
@Test
public void testClearCache() {
//1、根据id查询用户
User user1 = userDao.findById(41);
System.out.println(user1);//com.song.domain.User@18ce0030
//2.1更新用户信息(执行此方法时会清空缓存,导致两次查询对象不是同一个)
user1.setUsername("update user clear cache");
user1.setAddress("北京市显示");
userDao.updateUser(user1);
//2.2重新获取SqlSession对象
// sqlSession.close();
// //再次获取sqlSession对象
// sqlSession = factory.openSession(true);
// userDao = sqlSession.getMapper(IUserDao.class);
//2.3清空缓存
// sqlSession.clearCache();//此方法可以清空缓存
//3、再次查询id为41的用户
User user2 = userDao.findById(41);
System.out.println(user2);//com.song.domain.User@25d250c6
System.out.println(user1==user2);//false
}
}
四、二级缓存
1、二级缓存使用步骤
第一步:让Mybatis框架支持二级缓存(SQLMapConfig.xml中配置)
<!-- 配置参数 -->
<settings>
<!-- 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 -->
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<!-- 开启user支持二级缓存 -->
<cache></cache>
第三步:让当前的操作支持二级缓存(在select标签中配置)
<!-- 根据id查询 -->
<select id="findById" parameterType="INT" resultType="User" useCache="true">
select * from user where id=#{id}
</select>
2、配置SQLMapConfig.xml支持缓存
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- 可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息 -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 配置参数 -->
<settings>
<!-- 开启Mybatis支持延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 使用typeAliases配置别名,它只能配置domain中类的别名-->
<!-- package:用于配置别名的包,当指定之后,该包下的实体类都会注册别名 类名就是别名不区分大小写 -->
<typeAliases><package name="com.song.domain"></package></typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置MySQL的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的四个基本信息 -->
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<!-- <mapper resource = "com/song/dao/IUserDao.xml"></mapper> -->
<!--package标签是用于指定dao接口所在的包 :当指定完成之后就不需要再写mapper以及resource或者class了-->
<package name="com.song.dao"></package>
</mappers>
</configuration>
3、配置IUserDao.xml支持二级缓存
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.song.dao.IUserDao">
<!-- 配置查询所有 -->
<!-- ①开启user支持二级缓存 -->
<cache></cache>
<!-- 查询所有 -->
<select id="findAll" resultType="User">
select * from user
</select>
<!-- ②根据id查询 -->
<select id="findById" parameterType="INT" resultType="User" useCache="true">
select * from user where id=#{id}
</select>
<!-- 修改用户地址和名字 -->
<update id="updateUser" parameterType="user">
update user set username=#{username},address=#{address} where id=#{id}
</update>
</mapper>
4、编写二级缓存测试类
public class SeconedCacheTest {
private InputStream in;
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
//1、读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory工厂(工厂模式)
factory= new SqlSessionFactoryBuilder().build(in);
//3、使用工厂生产SqlSesson对象
//sqlSession = factory.openSession(true);//手动将事务提交方式改为自动提交
//4、使用SqlSession创建Dao接口的代理对象
//userDao = sqlSession.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destory() throws Exception {
//提交事务
//sqlSession.commit();
//6、释放资源
//sqlSession.close();
in.close();
}
/**
* 测试一级缓存
*/
@Test
public void testFirstCache() {
SqlSession sqlSession1 = factory.openSession(true);
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = userDao1.findById(41);
System.out.println(user1);//com.song.domain.User@18ce0030
sqlSession1.close();//一级缓存消失
SqlSession sqlSession2 = factory.openSession(true);
IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = userDao2.findById(41);
System.out.println(user2);//com.song.domain.User@5dd6264
System.out.println(user1==user2);//false
System.out.println(user1.getAddress().equals(user2.getAddress()));//true
}
}
5、二级缓存测试结果说明
6、二级缓存测试控制台说明
经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。
7、 二级缓存注意事项
当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式
来保存对象。
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
五、基于注解的二级缓存配置
1、配置SQLMapConfig.xml
<!-- 配置开启二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2、持久层接口
//mybatis 基于注解方式实现配置二级缓存
@CacheNamespace(blocking = true)
public interface IUserDao {
//根据id查询
@Select("select * from user where id=#{uid}")
User findById(Integer id);
}