mybatis的有两种缓存,一级缓存和二级缓存。两个缓存的不同点和相同点总结如下
不同点:
- 一级缓存存在于一个SqlSession之内,二级缓存存在于不同的SqlSession之间
- 一级缓存不需要手动开启,属于默认开启状态;二级缓存需要手动开启
相同点:
- 在增删改SQL之后,缓存会自动清空
- flushCache="true"的查询语句查询内容不存放进缓存
一级缓存
一级缓存是mybatis自带的缓存,mybatis每次在查询后,会将语句和参数相同的查询SQL的结果集存放进缓存,待下一次有相同的语句和参数时,mybatis直接将缓存内的结果集返回,而不再查询数据库。如果对于缓存的数据对应的表有增删改操作的话,缓存自动清空。
通过实际的代码测试来看,在上一次一个简单的mybatis入门demo的基础上改造工程
增加BaseMaperTest.java类,用以进行SqlSession的获取
package cn.mybatis.xml;
import java.io.IOException;
import java.io.Reader;
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 org.junit.BeforeClass;
/**
* 设置mapper测试父类
* 用以进行数据库连接,获取SqlSession
* @author PC
*/
public class BaseMapperTest {
private static SqlSessionFactory sqlSessionFactory;
/**
* 进行数据库连接
*/
@BeforeClass
public static void init() {
try {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession
* @return
*/
public SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
在CountryMapper.java中增加根据id查询方法,增加一个addCountry方法
/**
* 查询国家/地区
* @param id 查询id
* @return 查询到的国家/地区
*/
Country selectCountryById(Long id);
/**
* 添加国家/地区
* @param country
* @return 影响的数据条数
*/
int addCountry(Country country);
对应CountryMapper.xml配置文件
<select id="selectCountryById" resultType="cn.mybatis.xml.model.Country">
select id, countryname, countrycode
from country
where id = #{id}
</select>
<insert id="addCountry">
insert into country(id, countryname, countrycode)
values(#{id}, #{countryname}, #{countrycode})
</insert>
通过Junit来测试,三种场景,分别来测试
- 缓存后,直接查询
/**
* 一级缓存测试
* 测试缓存后,再查询
*/
@Test
public void testCache1() {
SqlSession sqlSession = getSqlSession();
try {
// 第一次查询
Country country = sqlSession.selectOne("selectCountryById", 2l);
System.out.println(country.getCountryname() + ":" + country.getCountrycode());
// 通过日志可以发现,第二次查询并未到数据库查数据,说明第二次走的是缓存
Country country2 = sqlSession.selectOne("selectCountryById", 2l);
System.out.println(country2.getCountryname() + ":" + country2.getCountrycode());
} finally {
sqlSession.close();
}
}
执行后,可以看到日志
Opening JDBC Connection
Created connection 1291113768.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4cf4d528]
==> Preparing: select id, countryname, countrycode from country where id = ?
==> Parameters: 2(Long)
<== Columns: id, countryname, countrycode
<== Row: 2, 美国, US
<== Total: 1
美国:US
美国:US
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4cf4d528]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4cf4d528]
Returned connection 1291113768 to pool.
反馈了两次查询结果,但是只查询了一次数据库,说明第二次的查询是取得缓存结