缓存机制(一级缓存)

        mybatis是基于JDBC的封装,数据库的操作更加的便捷,mybatis除了对JDBC的操作步骤进行封装之外也对其性能进行了优化,在mybatis引入缓存机制,用于提升mybatis的检索效率,而缓存的原理简单地说就是将存储数据的内存

一级缓存:

        一级缓存,也叫SqlSession级缓存,无需手动开启可直接使用,为每个sqlsession单独分配的缓存空间,多个sqlsession之间的缓存不共享

mybatisUntil工具类:

        由于无论一级缓存还是二级缓存都是基于工具类展开的,所以在整理之前,在这里先附上mybatisUntil工具类的封装代码~而关于缓存机制的整理主要将会根据其特性进行展开

package com.qhit.Untils;

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 java.io.IOException;
import java.io.InputStream;

/**
 * Description: NewSsm
 * Created by WuHuaSen .
 * Created Date:  2022/4/1 16:23
 * Version:  V1.0
 */
public class MybatisUtil {
    //封装会话工厂
    private static SqlSessionFactory Factory;
    /**在进行对象的跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束
     */
    private static ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();

    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            Factory = sqlSessionFactoryBuilder.build(is);

        } catch (
                IOException e)

        {
            e.printStackTrace();
        }
    }
    //封装factory方法
    public  static SqlSessionFactory getFactory(){
        return Factory;
    }

    //封装sqlSession会话
    public static SqlSession getSqlSession(boolean IsAutoComiit) {
        SqlSession sqlSession = local.get();
        if (sqlSession == null) {
            sqlSession = Factory.openSession(IsAutoComiit);
            local.set(sqlSession);
        }
        return sqlSession;
    }

    //使用泛型封装getMapper
    public static <T extends Object> T getMapper(Class<T> c) {
        SqlSession sqlSession = getSqlSession(true);
        return sqlSession.getMapper(c);
    }
}

案例需求: 

        案例为:“通过会员店ID进行用户信息的查询”;接下来将通过具体的实例来走进mybatis缓存机制,下面代码是对接口类(Dao层)以及接口的映射实现

MemberDao接口MemberDaoMapper.xml
package com.qhit.Dao;

import com.mysql.fabric.xmlrpc.base.Params;
import com.qhit.pojo.Member;
import com.qhit.pojo.MemberSearchCondition;
import org.apache.ibatis.annotations.Param;
import org.omg.CORBA.Object;

import java.util.HashMap;
import java.util.List;

public interface MemberDao {
   //修改方法-根据id修改年龄
public  int UpdateMemberById(@Param("MemberId") int MemberId,@Param("MemberAge") int MemberAge);

//根据会员ID查询
public  List<Member> SearchMemberById(int MemberId);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qhit.Dao.MemberDao">
    <sql id="Member_colum_List">
member_id,member_nick,member_gender,member_age,member_city
    </sql>  
    <!--修改操作-->
    <update id="UpdateMemberById" parameterType="java.lang.Integer">
        UPDATE member SET member_age = #{MemberAge} WHERE  member_id = #{MemberId};
    </update>
    <!--根据会员id进行查询-->
    <select id="SearchMemberById" resultMap="MemberMap">
        select <include refid="Member_colum_List"/> from member WHERE member_id = #{MemberId};
    </select>
</mapper>     

一级缓存的特性:

        特性1:

        如果多次查询使用的同一个sqlsession对象,第一次查询之后数据会被存放到缓存,后续的查询会直接访问缓存中的存储数据,如果查不到才会访问数据库;

package com.qhit.Dao;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qhit.Untils.MybatisUtil;
import com.qhit.pojo.Member;
import com.qhit.pojo.MemberSearchCondition;
import com.sun.xml.internal.ws.api.model.MEP;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Description: member_RemSql
 * Created by WuHuaSen .
 * Created Date:  2022/4/7 8:31
 * Version:  V1.0
 */
public class MemberDaoTest {
    MybatisUtil mybatisUtil = new MybatisUtil();
    @Test
    //根据i会员id进行查询
    public void SearchMemberById() {
        //通过封装会话获取第一个sqlsession
        SqlSession sqlSession1 = mybatisUtil.getSqlSession(true);
        //通过封装会话获取第二个sqlsession
        SqlSession sqlSession2 =  mybatisUtil.getSqlSession(true);
        ;
        //通过第一个sqlsession1获取getMapper
        MemberDao memberDao01 = sqlSession1.getMapper(MemberDao.class);
        //通过第二个sqlsession2获取getMapper
        MemberDao memberDao02 = sqlSession2.getMapper(MemberDao.class);
        //通过memberDao01实现第一次查询
        List<Member> members01 = memberDao01.SearchMemberById(1);
        for (Member m1 : members01
                ) {
            System.out.println(m1);
        }
        //通过memberDao02实现第二次查询
        List<Member> members02 = memberDao02.SearchMemberById(1);
        System.out.println(memberDao02);
        for (Member m2 : members02
                ) {
            System.out.println(m2);
        }


    }
}

        由于sqlsession是通过getSqlSession(boolean IsAutoComiit)方法直接获取,根据查看工具类我们可以知道,虽然这里我们获取了两次getSqlSession(boolean IsAutoComiit)方法,但是获取到的sqlsession是同一个;所以第二次实现查询方法的时候,会直接从缓存中获取数据~

         当我们获取不同的sqlsession时,不同的sqlsession之间缓存并不会共享,所以每次都会从数据库中获取查询数据

package com.qhit.Dao;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qhit.Untils.MybatisUtil;
import com.qhit.pojo.Member;
import com.qhit.pojo.MemberSearchCondition;
import com.sun.xml.internal.ws.api.model.MEP;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Description: member_RemSql
 * Created by WuHuaSen .
 * Created Date:  2022/4/7 8:31
 * Version:  V1.0
 */
public class MemberDaoTest {
    MybatisUtil mybatisUtil = new MybatisUtil();
    @Test
    //根据i会员id进行查询
    public void SearchMemberById() {
        //通过封装会话工厂获取第一个sqlsession
        SqlSession sqlSession1 = mybatisUtil.getFactory().openSession();
        //通过封装会话工厂获取第二个sqlsession
        SqlSession sqlSession2 = mybatisUtil.getFactory().openSession();
        ;
        //通过第一个sqlsession1获取getMapper
        MemberDao memberDao01 = sqlSession1.getMapper(MemberDao.class);
        //通过第二个sqlsession2获取getMapper
        MemberDao memberDao02 = sqlSession2.getMapper(MemberDao.class);
        //通过memberDao01实现第一次查询
        List<Member> members01 = memberDao01.SearchMemberById(1);
        for (Member m1 : members01
                ) {
            System.out.println(m1);
        }
        //通过memberDao02实现第二次查询
        List<Member> members02 = memberDao02.SearchMemberById(1);
        System.out.println(memberDao02);
        for (Member m2 : members02
                ) {
            System.out.println(m2);
        }


    }
}

 特性2:

        如果第一次查询之后对查询出的对象进行修改(修改数据库中的数据),会造成第一次查询的结果和第二次查询结果不同

package com.qhit.Dao;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qhit.Untils.MybatisUtil;
import com.qhit.pojo.Member;
import com.qhit.pojo.MemberSearchCondition;
import com.sun.xml.internal.ws.api.model.MEP;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Description: member_RemSql
 * Created by WuHuaSen .
 * Created Date:  2022/4/7 8:31
 * Version:  V1.0
 */
public class MemberDaoTest {
    MybatisUtil mybatisUtil = new MybatisUtil();
    @Test
    //根据i会员id进行查询
    public void SearchMemberById() {
        //通过封装会话获取第一个sqlsession
        SqlSession sqlSession1 = mybatisUtil.getSqlSession(true);
        //通过封装会话获取第二个sqlsession
        SqlSession sqlSession2 =  mybatisUtil.getSqlSession(true);
        //新开一个Ssqlsession,用于修改
        SqlSessionFactory factory = mybatisUtil.getFactory();
        SqlSession sqlSession3 =factory.openSession();
        //通过第一个sqlsession1获取getMapper
        MemberDao memberDao01 = sqlSession1.getMapper(MemberDao.class);
        //通过第二个sqlsession2获取getMapper
        MemberDao memberDao02 = sqlSession2.getMapper(MemberDao.class);
        //通过第三个sqlsession3获取getMapper
        MemberDao memberDao03 = sqlSession3.getMapper(MemberDao.class);
        //通过memberDao01实现第一次查询
        List<Member> members01 = memberDao01.SearchMemberById(1);
        for (Member m1 : members01
                ) {
            System.out.println(m1);
        }
        //通过member03实现修改
        int i =memberDao03.UpdateMemberById(1,24);
        //通过memberDao02实现第二次查询
        List<Member> members02 = memberDao02.SearchMemberById(1);
        System.out.println(memberDao02);
        for (Member m2 : members02
                ) {
            System.out.println(m2);
        }


    }


}

        根据id(id=1)进行第一次查询,查询之后会把结果存放到缓存中,在第一次查询之后调用修改方法,此修改方法使用的sqlsession与查询所使用的不是同一个,在使用查询的sqlsession进行第二次查询,这是可以看到,虽然我们的数据库数据已经发生改变,但是第二次查询结果却与第一次保持了一致,这是因为,第二次查询并没有访问数据库,而是从缓存中直接获取了数据,进行了打印输出

 特性三:

        当我们进行查询的时候想要跳过缓存直接获取数据库则可以通过sqlsession.clearCache();来清楚当前sqlsession缓存,

package com.qhit.Dao;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qhit.Untils.MybatisUtil;
import com.qhit.pojo.Member;
import com.qhit.pojo.MemberSearchCondition;
import com.sun.xml.internal.ws.api.model.MEP;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Description: member_RemSql
 * Created by WuHuaSen .
 * Created Date:  2022/4/7 8:31
 * Version:  V1.0
 */
public class MemberDaoTest {
    MybatisUtil mybatisUtil = new MybatisUtil();

    @Test
    //根据i会员id进行查询
    public void SearchMemberById() {
        //通过封装会话获取第一个sqlsession
        SqlSession sqlSession1 = mybatisUtil.getSqlSession(true);
        //新开一个Ssqlsession,用于修改
        SqlSessionFactory factory = mybatisUtil.getFactory();
        SqlSession sqlSession3 =factory.openSession();
        //通过第一个sqlsession1获取getMapper
        MemberDao memberDao01 = sqlSession1.getMapper(MemberDao.class);
        //通过第三个sqlsession3获取getMapper
        MemberDao memberDao03 = sqlSession3.getMapper(MemberDao.class);
        //通过memberDao01实现第一次查询
        List<Member> members01 = memberDao01.SearchMemberById(2);
        sqlSession1.clearCache();
        for (Member m1 : members01
                ) {
            System.out.println(m1);
        }
        //通过member03实现修改
        int i =memberDao03.UpdateMemberById(2,25);
        //通过memberDao02实现第二次查询
        List<Member> members02 = memberDao01.SearchMemberById(2);
        System.out.println(memberDao01);
        for (Member m2 : members02
                ) {
            System.out.println(m2);
        }


    }

}

        清空内存后,再进行查询会从数据库重新获取数据,实现了数据的一致性~

解决方案 :

1、让修改和查询操作使用相同的sqlsession,但是由于项目servlet中是单例模式,所以此方法不太合理

2、每次进行查询操作之后,清空缓存,让再次进行的查询的时候绕过缓冲直接访问数据库。

3、使用二级缓存~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MyBatis的三级缓存机制指的是MyBatis在执行SQL语句时,会默认启用三级缓存,以提高查询性能。 三级缓存分别是: 1. 一级缓存:也称为本地缓存,指的是MyBatis在同一次会话中执行相同SQL语句时,会将结果缓存到内存中,下次查询相同的SQL语句时,直接从缓存中读取结果,而不会再次执行SQL语句。一级缓存的作用域是会话级别的。 2. 二级缓存:也称为全局缓存,指的是MyBatis在多次会话中执行相同SQL语句时,会将结果缓存到内存中,下次查询相同的SQL语句时,直接从缓存中读取结果,而不会再次执行SQL语句。二级缓存的作用域是Mapper级别的。 3. 三级缓存:也称为分布式缓存,指的是MyBatis在多个应用程序之间共享缓存,以提高查询性能。三级缓存的作用域是全局级别的,需要使用第三方缓存组件来实现。 需要注意的是,三级缓存在默认情况下是关闭的,需要手动开启。开启方法如下: 在mybatis-config.xml文件中添加如下配置: ``` <settings> <setting name="cacheEnabled" value="true"/> <setting name="localCacheScope" value="SESSION"/> <setting name="lazyLoadingEnabled" value="true"/> </settings> ``` 其中,cacheEnabled表示是否开启缓存,localCacheScope表示一级缓存的作用域,lazyLoadingEnabled表示是否启用延迟加载。 需要注意的是,开启二级缓存时,需要在Mapper.xml文件中添加如下配置: ``` <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> ``` 其中,type属性指定了缓存的类型,这里使用了EhcacheCache。需要在项目中添加Ehcache的依赖。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暇光曙墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值