像大多數的持久化框架一樣,Mybatis 也提供了緩存策略,通過緩存策略來減少數據庫的查詢次數,從而提高性能
Mybatis 中緩存分爲一級緩存,二級緩存
Mybatis 一級緩存
一級緩存是 SqlSession 級別的緩存,只要 SqlSession 沒有 flush 或 close,它就存在。
證明一級緩存的存在
新建數據庫映射實體類 User.java
package cn.lemon.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
新建持久層接口 IUserDao.java
package cn.lemon.dao;
import cn.lemon.domain.User;
public interface IUserDao {
User findById(Integer userId);
}
新建配置文件 SqlMapConfig.xml 和 jdbc.properties
<?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">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="cn.lemon.domain"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="cn.lemon.dao"/>
</mappers>
</configuration>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///db_mybatis
jdbc.username=root
jdbc.password=lemon
新建接口映射文件 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="cn.lemon.dao.IUserDao">
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
測試類
package cn.lemon.dao;
import cn.lemon.domain.User;
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.Test;
import java.io.InputStream;
public class IUserDaoTest {
private InputStream inputStream;
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
private IUserDao iUserDao;
@Test
public void findById() throws Exception{
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession(true);
iUserDao = sqlSession.getMapper(IUserDao.class);
/*第一次查詢*/
User user1 = iUserDao.findById(58);
System.out.println("第一次查詢:" + user1);
System.out.println("-------------------------------------------");
/*第二次查詢*/
User user2 = iUserDao.findById(58);
System.out.println("第二次查詢:" + user2);
sqlSession.close();
inputStream.close();
}
}
運行結果:
關閉緩存,或者使用sqlSession.clearCache
清除緩存,或者對查詢的這條語句執行修改,就會出現兩次查詢
Mybatis 二級緩存 (重要)
二級緩存的特點
- 二級緩存是 mapper 映射級別的緩存
- 多個 SqlSession 去操作同一個 Mapper 映射的 sql 語句
- 多個SqlSession 可以共用二級緩存
- 二級緩存是跨 SqlSession 的。
二級緩存的配置
第一步:在 SqlMapConfig.xml 文件開啓二級緩存
<settings>
<!--
開啓二級緩存的支持
因爲 cacheEnabled 的取值默認就爲 true,所以這一步可以省略不配置。爲 true 代表開啓二級緩存;爲 false 代表不開啓二級緩存
-->
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:在 IUserDao.xml 中,配置相關的 Mapper 映射文件
<!--
開啓二級緩存的支持
<cache>標籤表示當前這個 mapper 映射將使用二級緩存,區分的標準就看 mapper 的 namespace
-->
<cache></cache>
第三步:在 IUserDao.xml 中,配置 statement 上面的 useCache 屬性
第四步:測試類
package cn.lemon.dao;
import cn.lemon.domain.User;
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.Test;
import java.io.InputStream;
public class IUserDaoTest {
@Test
public void findById() throws Exception {
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/*第一次查詢*/
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
IUserDao iUserDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = iUserDao1.findById(58);
System.out.println("第一次查詢:" + user1);
System.out.println("-------------------------------------------");
sqlSession1.close();//關閉資源
/*第二次查詢*/
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);//重新開啓
IUserDao iUserDao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = iUserDao2.findById(58);
System.out.println("第二次查詢:" + user2);
System.out.println("-------------------------------------------");
sqlSession2.close();
/*第三次查詢*/
SqlSession sqlSession3 = sqlSessionFactory.openSession(true);//重新開啓
IUserDao iUserDao3 = sqlSession3.getMapper(IUserDao.class);
User user3 = iUserDao3.findById(58);
System.out.println("第三次查詢:" + user3);
System.out.println("-------------------------------------------");
sqlSession3.close();
inputStream.close();
}
}
運行結果:
特別提醒:
- 二級緩存要實現序列化接口,也就是
implements Serializable
- 二級緩存要在同一個命名空間下,不用的命名空間有不同的緩存,如上面的例子
namespace="cn.lemon.dao.IUserDao"