目录
一、什么是缓存?
缓存(cache),数据交换的缓冲区,当应用程序需要读取数据时,先从数据库中将数据取出,放置在 缓冲区中,应用程序从缓冲区读取数据。
Cache的特点:数据库取出的数据保存在内存中,具备快速读取和使用。
Cache的限制:读取时无需再从数据库获取,数据可能不是最新的。
二、什么是一级缓存?
一级缓存也叫SqlSession级缓存,无需手动开启可直接使用,为每个SqlSession单独分配的缓存空间,多个SqlSession之间的缓存不共享。
一级缓存实例如下:
1.JavaBean类:
package com.ape.bean;
import java.util.Date;
public class Student {
private String sid;
private String sname;
private Date birthday;
private String ssex;
private int classid;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSsex() {
return ssex;
}
public void setSsex(String ssex) {
this.ssex = ssex;
}
public int getClassid() {
return classid;
}
public void setClassid(int classid) {
this.classid = classid;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String sid, String sname, Date birthday, String ssex, int classid) {
super();
this.sid = sid;
this.sname = sname;
this.birthday = birthday;
this.ssex = ssex;
this.classid = classid;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", birthday=" + birthday + ", ssex=" + ssex + ", classid="
+ classid + "]";
}
}
2.Dao层:
package com.ape.dao;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class DaoUtil {
private static SqlSessionFactory build;
static {
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
build = new SqlSessionFactoryBuilder().build(resourceAsStream);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return build.openSession();
}
public static void closeResource(SqlSession sqlSession) {
sqlSession.close();
}
}
3.mapper层:
package com.ape.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;
import com.ape.bean.Student;
public interface IStudentMapper {
//通过sid查询学生表中的数据
@Select("select * from student where sid = #{sid}")
List<Student> findStudentBySid(int sid);
//通过sid删除学生表中的数据
@Delete("delete from student where sid = #{sid}")
int deleteStudentBySid(int sid);
}
4.view层:
package com.ape.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.ape.bean.Student;
import com.ape.dao.DaoUtil;
import com.ape.mapper.IStudentMapper;
public class Test1 {
public static void main(String[] args) {
SqlSession sql = DaoUtil.getSqlSession();
IStudentMapper mapper = sql.getMapper(IStudentMapper.class);
//第一次通过sid查询对应的数据
List<Student> findStudentBySid1 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid1);
System.out.println("----------------------------------------------------------");
//第二次通过sid查询对应的数据
List<Student> findStudentBySid2 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid2);
//释放资源
sql.close();
}
}
运行结果:
什么情况下一级缓存会失效?
1.用的不是同个SqlSession
package com.ape.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.ape.bean.Student;
import com.ape.dao.DaoUtil;
import com.ape.mapper.IStudentMapper;
public class Test1 {
public static void main(String[] args) {
//第一个SqlSession
SqlSession sql1 = DaoUtil.getSqlSession();
IStudentMapper mapper1 = sql1.getMapper(IStudentMapper.class);
List<Student> findStudentBySid1 = mapper1.findStudentBySid(1);
System.out.println(findStudentBySid1);
System.out.println("-----------------------------------------------------------------------------------------------------");
//第二个SqlSession
SqlSession sql2 = DaoUtil.getSqlSession();
IStudentMapper mapper2 = sql2.getMapper(IStudentMapper.class);
List<Student> findStudentBySid2 = mapper2.findStudentBySid(1);
System.out.println(findStudentBySid2);
//释放资源
sql1.close();
sql2.close();
}
}
2.同一个SqlSession单查询条件不同
package com.ape.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.ape.bean.Student;
import com.ape.dao.DaoUtil;
import com.ape.mapper.IStudentMapper;
public class Test1 {
public static void main(String[] args) {
SqlSession sql = DaoUtil.getSqlSession();
IStudentMapper mapper = sql.getMapper(IStudentMapper.class);
//第一种单查询条件sid=1
List<Student> findStudentBySid1 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid1);
System.out.println("----------------------------------------------------------");
//第二种单查询条件sid=2
List<Student> findStudentBySid2 = mapper.findStudentBySid(2);
System.out.println(findStudentBySid2);
//释放资源
sql.close();
}
}
3.同一个SqlSession做了增删改
package com.ape.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.ape.bean.Student;
import com.ape.dao.DaoUtil;
import com.ape.mapper.IStudentMapper;
public class Test1 {
public static void main(String[] args) {
SqlSession sql = DaoUtil.getSqlSession();
IStudentMapper mapper = sql.getMapper(IStudentMapper.class);
//第一次通过sid查询对应的数据
List<Student> findStudentBySid1 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid1);
//通过sid做一次删除操作
int a = mapper.deleteStudentBySid(2);
if (a > 0) {
sql.commit();
System.out.println("删除成功!");
}else {
sql.rollback();
System.out.println("删除失败!");
}
System.out.println("----------------------------------------------------------");
//第二次通过sid查询对应的数据
List<Student> findStudentBySid2 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid2);
//释放资源
sql.close();
}
}
4.主动清空了缓存()
package com.ape.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.ape.bean.Student;
import com.ape.dao.DaoUtil;
import com.ape.mapper.IStudentMapper;
public class Test1 {
public static void main(String[] args) {
SqlSession sql = DaoUtil.getSqlSession();
IStudentMapper mapper = sql.getMapper(IStudentMapper.class);
//第一次通过sid查询对应的数据
List<Student> findStudentBySid1 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid1);
//主动清空缓存
sql.clearCache();
System.out.println("----------------------------------------------------------");
//第二次通过sid查询对应的数据
List<Student> findStudentBySid2 = mapper.findStudentBySid(1);
System.out.println(findStudentBySid2);
//释放资源
sql.close();
}
}
三、什么是二级缓存?
是mybatis的另一种缓存机制,区别于一级缓存,它是namespace级别,即一个mapper一个缓存,相互独立,互不影响,同一namespace下的多个sqlSession可以共享缓存,默认不开启,需要配置开启。
1.Mybatis中二级缓存的开启步骤:
1.1 在xml中开启
(1)在mybatis的sqlMapConfig.xml 中配置:
(2)在mybatis的sqlmap中配置(mapper.xml中配置):
(3)在使用的操作中配置(例如在select标签中配置)
1.2 在注解中开启
(1)在mybatis的sqlMapConfig.xml 中配置
(2)在接口的定义上面直接使用@CacheNamespace 并将blocking设置为true
二级缓存总结:
1.Mybatis 的二级缓存相对于一级缓存来说,实现了缓存数据的共享,可控性也更强。
2.极大可能会出现错误数据,有设计上的缺陷,安全使用的条件比较苛刻。
3.分布式环境下,必然会出现读取到错误数据,所以不推荐使用,了解即可。
四、一级缓存和二级缓存的区别
1.一级缓存是SqlSession级别的而二级缓存是SqlSessionFactory级别的
2.一级缓存写到了内存中而二级缓存直接序列化把写到了磁盘中
3.一级缓存自动开启,二级缓存需要手动开启