05.SSM框架集~Mybatis(三)
本文是上一篇文章的后续,详情点击该链接
Mybatis 1 ~ 3 源码 提取码:pmbr
缓存
缓存(cache),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。缓存的设置是所有现代计算机系统发挥高性能的重要因素之一。
是一种临时存储少量数据至内存或者是磁盘的一种技术.减少数据的加载次数,可以降低工作量,提高程序响应速度
缓存的重要性是不言而喻的。mybatis的缓存将相同查询条件的SQL语句执行一遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询SQL时候不在执行SQL与数据库交互,而是直接从缓存中获取结果,减少服务器的压力;尤其是在查询越多、缓存命中率越高的情况下,使用缓存对性能的提高更明显。
MyBatis允许使用缓存,缓存一般放置在高速读/写的存储器上,比如服务器的内存,能够有效的提供系统性能。MyBatis分为一级缓存和二级缓存,同时也可配置关于缓存设置。
一级存储是SqlSession上的缓存,二级缓存是在SqlSessionFactory(namespace)上的缓存。默认情况下,MyBatis开启一级缓存,没有开启二级缓存。当数据量大的时候可以借助一些第三方缓存框架或Redis缓存来协助保存Mybatis的二级缓存数据。
一级缓存
一级存储是SqlSession上的缓存,默认开启,是一种内存型缓存,不要求实体类对象实现Serializable接口。s下面在没有任何配置的情况下,测试一级缓存。
接口
Student FindBySon(String son);
Mapper
<select id="FindBySon" resultType="student">
select * from student where son = #{son}
</select>
Java
public static void cache(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.FindBySon("666666");
System.out.println(student);
//假如此处做了增删改
/*commit方法会刷新一级缓存
* 和事务是否自动提交没有关系
* */
sqlSession.commit();
StudentMapper mapper2 = sqlSession.getMapper(StudentMapper.class);
Student student2 = mapper2.FindBySon("666666");
System.out.println(student2);
/*
* 多个同namespace下的mapper 只要来自于同一个sqlsession就可以公用以及缓存
* */
System.out.println(mapper==mapper2);
sqlSession.close();
}
二级缓存
二级缓存是以namespace为标记的缓存,可以是由一个SqlSessionFactory创建的SqlSession之间共享缓存数据。默认并不开启。下面的代码中创建了两个SqlSession,执行相同的SQL语句,尝试让第二个SqlSession使用第一个SqlSession查询后缓存的数据。
public static void caches(){
/*使用第一个sqlsession去查询数据*/
SqlSession sqlSession = SqlSessionUtil.getSqlSession(false);
StudentMapper mapper = sqlSession.getMapper( StudentMapper.class);
Student student = mapper.FindBySon("666666");
System.out.println(student);
// sqlSession.commit();
sqlSession.close();
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*使用第二个sqlsession查询数据*/
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession(false);
StudentMapper mapper2 = sqlSession2.getMapper( StudentMapper.class);
Student student2 = mapper2.FindBySon("666666");
System.out.println(student2);
sqlSession2.close();
}
注意其中的commit(),执行该命令后才会将该SqlSession的查询结果从一级缓存中放入二级缓存,供其他SqlSession使用。另外执行SqlSession的close()也会将该SqlSession的查询结果从一级缓存中放入二级缓存。两种方式区别在当前SqlSession是否关闭了。
执行结果显示进行了两次对数据库的SQL查询,说明二级缓存并没有开启。需要进行如下步骤完成开启。
(1) 全局开关:在mybatis.xml文件中的标签配置开启二级缓存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
(2) 分开关:在要开启二级缓存的mapper文件中开启缓存:
<mapper namespace="com.alvin.studentmapper.StudentMapper">
<cache/>
</mapper>
(3) 二级缓存未必完全使用内存,有可能占用硬盘存储,缓存中存储的JavaBean对象必须实现序列化接口,
public class Student implements Serializable {
private String son;
private String realname;
private String password;
private String classname;
private Double score;
}
经过设置后,查询结果如图所示。发现第一个SqlSession会首先去二级缓存中查找,如果不存在,就查询数据库,在commit()或者close()的时候将数据放入到二级缓存。第二个SqlSession执行相同SQL语句查询时就直接从二级缓存中获取了。
注意:
(1) MyBatis的二级缓存的缓存介质有多种多样,而并不一定是在内存中,所以需要对JavaBean对象实现序列化接口。
(2) 二级缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响
(3) 加入Cache元素后,会对相应命名空间所有的select元素查询结果进行缓存,而其中的insert、update、delete在操作是会清空整个namespace的缓存。
(4) cache 有一些可选的属性 type, eviction, flushInterval, size, readOnly, blocking。
<cache type="" readOnly="" eviction=""flushInterval=""size=""blocking=""/>
属性 | 含义 | 默认值 |
type | 自定义缓存类,要求实现org.apache.ibatis.cache.Cache接口 | null |
readOnly | 是否只读 true:给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。 false:会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全 | false |
eviction | 缓存策略
LRU(默认) – 最近最少使用:移除最长时间不被使用的对象。 FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。 WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。 |
LRU |
flushInterval | 刷新间隔,毫秒为单位。默认为null,也就是没有刷新间隔,只有执行update、insert、delete语句才会刷新 | null |
size | 缓存对象个数 | 1024 |
blocking | 是否使用阻塞性缓存BlockingCache true:在查询缓存时锁住对应的Key,如果缓存命中了则会释放对应的锁,否则会在查询数据库以后再释放锁,保证只有一个线程到数据库中查找指定key对应的数据 false:不使用阻塞性缓存,性能更好 |
false |
(5)如果在加入Cache元素的前提下让个别select 元素不使用缓存,可以使用useCache属性,设置为false。useCache控制当前sql语句是否启用缓存 flushCache控制当前sql执行一次后是否刷新缓存
<select id="FindBySon()" resultType="student" useCache="true" flushCache="false">
MyBatis注解开发
MyBatis编写SQL除了使用Mapper.xml还可以使用注解完成。当可以使用Auto Mapping时使用注解非常简单,不需要频繁的在接口和mapper.xml两个文件之间进行切换。但是必须配置resultMap时使用注解将会变得很麻烦,这种情况下推荐使用mapper.xml进行配置。
MyBatis支持纯注解方式,支持纯mapper.xml方式,也支持注解和mapper.xml混合形式。当只有接口没有mapper.xml时在mybatis.cfg.xml中可以通过加载接口类。如果是混合使用时,使用。此方式一直是官方推荐方式。
如果某个功能同时使用两种方式进行配置,XML方式将覆盖注解方式
使用注解完成之前的增删查改操作
这一次我们只需要一个接口即可,无需StudentMapper.xml
Mapper接口
public interface StudentMapper {
//查询全部学生信息
@Select("select * from student")
List<Student> FindAll();
//增加学生信息
@Insert("insert into student value(#{son},#{realname},#{password},#{classname},#{score})")
int Insert(Student student);
//删除学生信息
@Delete("delete from student where son = #{son}")
int delete(String son);
//修改学生信息
@Update("update student set realname = #{realname}, password = #{password},classname = #{classname},score = #{score} where son = #{son};")
int change(Student student);
//查询单个学生信息
@Select("select * from student where son = #{son};")
Student FindByOn(String son);
//模糊查询
@Select("select * from student where realname like concat('%',#{realname},'%')")
List<Student> getByName(String realname);
}
代码测试
public class Test {
public static void main(String[] args) {
//Del();
//FindAll();
//Insert();
//Update();
//Find();
Fin();
}
//模糊查询
public static void Fin(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//查询姓名包含张的学生
List<Student> students = mapper.getByName("张");
//遍历
Iterator iterator = students.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
sqlSession.close();
}
//查询全部学生信息
public static void FindAll(){
//查询全部学生信息
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
// 帮助我们生成一个接口下的实现类对象的
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 接收数据
List<Student> list = studentMapper.FindAll();
//关闭sqlSession
sqlSession.close();
//遍历结果
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//新增学生信息
public static void Insert(){
//当执行增删改时,就需要提交True,否则无法完成操作!
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//需要新增的信息
Student student = new Student("666666","黄贵根","666666","信息工程学院",533.0);
//调用新增
int n = studentMapper.Insert(student);
//关闭sqlSession
sqlSession.close();
//处理结果
String str = n > 0 ? "新增成功!" : "新增失败!";
System.out.println(str);
}
//修改学生信息
public static void Update(){
//当执行增删改时,就需要提交True,否则无法完成操作!
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//需要修改的信息
Student student = new Student("666666","黄贵根","123456","信息工程学院",600.0);
//调用修改
int n = studentMapper.change(student);
//关闭sqlSession
sqlSession.close();
//处理结果
String str = n > 0 ? "修改成功!" : "修改失败!";
System.out.println(str);
}
//删除学生信息
public static void Del(){
//当执行增删改时,就需要提交True,否则无法完成操作!
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//调用删除
int n = studentMapper.delete("666666");
//关闭sqlSession
sqlSession.close();
//处理结果
String str = n > 0 ? "删除成功!" : "删除失败!";
System.out.println(str);
}
//查找学生信息
public static void Find(){
//查询操作则无需提交
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//调用查询
Student student = studentMapper.FindByOn("154787");
//关闭sqlSession
sqlSession.close();
//处理结果
String str = student != null ? student.toString() : "没找到!";
System.out.println(str);
}
}
注解和XML对比:
XML:
1.类和类之间的解耦
2.利于修改。直接修改XML文件,无需到源代码中修改。
3.配置集中在XML中,对象间关系一目了然,利于快速了解项目和维护
4.容易和其他系统进行数据交交换
注解:
1.简化配置
2.使用起来直观且容易,提升开发效率
3.类型安全,编译器进行校验,不用等到运行期才会发现错误。
4.注解的解析可以不依赖于第三方库,可以之间使用Java自带的反射