Mybatis入门学习记录(三):mybatis缓存及使用

在说动态SQL前,我补充一下之前没有将的mybatis的缓存,嘿嘿~

一、mybatis缓存

在开讲之前,我先说一句:mybatis的缓存不是目前大家所能见到的软件会普遍使用的,因为mybatis缓存只是在每个人的电脑中存在,换一台电脑这个缓存就无啦!对减轻数据库压力基本没有什么帮助!只是大致的了解一下是怎么回事!因为软件开发市场上目前的主流是缓存服务器,像redis、noSQL等!这个我画一张图解释一下,就是这样:

mybatis的缓存:

分为一级缓存: 无法关闭,默认打开 缓存在SqlSession对象

二级缓存: 以Mapper的namespace分类, 同一个namespace的数据缓存到二级缓存,

Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象

不同sqlSession,查询相同的statement, 走二级缓存, 数据可以共享

mybatis 的二级缓存默认是关闭。

开启mybatis的二级缓存:

1) 在Mybatis的全局配置文件中,允许使用二级缓存

 <settings>
        <!--允许使用二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

2) 在使用二级缓存的sql映射文件中使用 <cache/> 表示该mapper开启二级缓存

  <!--对该mapper开启二级缓存-->
    <cache/>

报错:

Caused by: java.io.NotSerializableException: com.fs.entity.User

原因: User实体类没有开启序列化

3) 对我们实体类实现序列化接口

@Data
public class User  implements Serializable {

对某个statement 禁用二级缓存:

select标签: 属性: useCache="true" 默认true, 使用缓存

useCache="false" 不使用缓存

  <select id="queryById" parameterType="int"  resultType="com.fs.entity.User" useCache="false">

自定义缓存框架:

1) 编写一个缓存类实现 org.apache.ibatis.cache.Cache接口

2) <cache type="指向的自定义缓存类包.类" />

之前的缓存框架: Ehcache

二、Mybatis的util工具类

核心类: SqlSessionFactory: 只能有一个

SqlSession: 每请求一次,创建一个SqlSession, 多例

每一次请求都有自己的SqlSession, 每一个线程都有自己的SqlSession

原因:SqlSession已关闭

引起原因: 多个线程共享了同一个SqlSession, SqlSession要线程隔离

ThreadLocal类

所以每个用户的电脑或者主机上都会有一个sqlSession用于存放自己访问这个APP时所使用的线程对象,我们可以根据这个SQLSession来实现多个请求多线程同时访问我们的数据库

 这是一个测试类用于测试多个线程同时访问发起请求,测试我们的多个SQLSession请求多线程访问我们的数据库会怎样(下面这个代码是已经完成的代码):

public class TestMybatisUtils {

    //开多个线程使用sqlSession

    public static void main(String[] args){
        new Thread(()->{
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            System.out.println("t1的SqlSession:"+sqlSession.hashCode());
            UserMapper userMapper =  sqlSession.getMapper(UserMapper.class);
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            User user = userMapper.queryById(1); //sqlSession.selectOne()
            System.out.println(user);

            MybatisUtils.closeSqlSession();
        }, "t1").start();

        new Thread(()->{
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            System.out.println("t2的SqlSession:"+sqlSession.hashCode());
            UserMapper userMapper =  sqlSession.getMapper(UserMapper.class);
            User user = userMapper.queryById(2);
            System.out.println(user);

            MybatisUtils.closeSqlSession();
        }, "t2").start();
    }
}

然后我们需要写一个mybatisUtils工具类用于实现每个用户发起请求时的在本地的sqlSession中存放相应的线程对象,并在合适的时候关闭它。

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    //private static SqlSession sqlSession;  //单例, 整个共享同一个SqlSession
    private static ThreadLocal<SqlSession> tl = new ThreadLocal<>();
    //

    static{
        InputStream in = null;
        try {
            in = Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 得到SqlSession方法
     */

    public static SqlSession getSqlSession(){
        //从当前执行的线程本地区获取SqlSession
        SqlSession sqlSession = tl.get();
        if( sqlSession== null){ //如果没有
            sqlSession = sqlSessionFactory.openSession(); //创建SqlSession
            tl.set(sqlSession);  //把创建SqlSession保存到当前线程的本地区
        }
        return sqlSession;
    }

    /**
     * 关闭SqlSession
     */
    public static void closeSqlSession(){
        SqlSession sqlSession = tl.get();
        if(sqlSession != null){
            sqlSession.commit();
            sqlSession.close();
            //把线程本地区的sqlSession移除
            tl.remove();
        }
    }


    /**
     * 得到指定Mapper类的对象
     * <T> 定义了泛型变量
     * T 使用泛型变量  返回值类型
     * Class<T>  T给泛型变量赋值
     */
    public static <T>  T getMapper(Class<T> clazz){
        return getSqlSession().getMapper(clazz);
    }
}

这样我们就能实现多线程访问数据库啦!我可能讲的还不是特别的清楚,所以希望大佬们看到了见谅,谢谢!感恩戴德!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值