05.SSM框架集~Mybatis(三)

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自带的反射

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章