范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Mybatis缓存模块

  Mybatis-缓存模块缓存模块要实现哪些功能Mybatis缓存的实现是基于Map的,从缓存里面读写数据是缓存模块的核心基础功能; 除核心功能之外,有很多额外的附加功能,如:防止缓存击穿,添加缓存清空策略(fifo、lru)、序列化功 能、日志能力、定时清空能力等; 附加功能可以以任意的组合附加到核心基础功能之上;
  这个模块因为有很多附加功能,而且这些功能是自由组合的所以Mybatis采用了装饰者模式。装饰者模式不太了解的可以看我之前的文章
  https://mp.toutiao.com/profile_v4/graphic/preview?pgc_id=7009090446181990949
  注意这里看的都是一级缓存
  这里查看几个主要的类: Cache : 对应装饰者的抽象组件 CacheKey: 实体类作为缓存的key PerpetualCache : 具体组件 BlockingCache :具体装饰器
  Cache public interface Cache {    // 缓存实现类的id   String getId();    // 往缓存中添加数据,这里的key是Object,key一般是CacheKey对象   void putObject(Object key, Object value);    // 根据指定的key从缓存获取数据   Object getObject(Object key);    Object removeObject(Object key);    void clear();    int getSize();      default ReadWriteLock getReadWriteLock() {     return null;   } }
  PerpetualCache : 这个类提供了基本的缓存功能 // PerpetualCache implements Cache // 缓存的map private final Map cache = new HashMap<>();  @Override public void putObject(Object key, Object value) {     cache.put(key, value); }
  BlockingCache public class BlockingCache implements Cache {      // 阻塞的超时时间     private long timeout;     // 被装饰的对象,一般是PerpetualCache(组件实现类)     private final Cache delegate;     // 锁对象集合,这里的颗粒度是key     private final ConcurrentHashMap locks;          // 放缓存信息这个行为不需要加锁   @Override   public void putObject(Object key, Object value) {     try {       delegate.putObject(key, value);     } finally {       releaseLock(key);     }   }    // 获取对象   @Override   public Object getObject(Object key) {     // 获取锁     acquireLock(key);     Object value = delegate.getObject(key);     if (value != null) {       // 数据获取成功后释放锁:从 lock集合中移除       releaseLock(key);     }     return value;   }         /**    * 这个方法在 3.5 版本的时候是基于 ReentrantLock 来处理的    * 本次看的版本为 3.8    * @param key    */   private void acquireLock(Object key) {     // 这里使用 CountDownLatch 多线程工具保证一个时间内只有一个线程在访问     CountDownLatch newLatch = new CountDownLatch(1);     while (true) {       // locks是  cuncurrentHashMap线程安全的容器,       // 调用 putIfAbsent,利用了容器特性,如果设置过则不会设置成功则会进入上面的自旋       CountDownLatch latch = locks.putIfAbsent(key, newLatch);       if (latch == null) {         break;       }       try {         // 判断是否有超时时间         if (timeout > 0) {           boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS);           if (!acquired) {             throw new CacheException(                 "Couldn"t get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId());           }         } else {           latch.await();         }       } catch (InterruptedException e) {         throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);       }     }   }    private void releaseLock(Object key) {     CountDownLatch latch = locks.remove(key);     if (latch == null) {       throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen.");     }     // 这里释 countDown 释放了锁     latch.countDown();   } }
  思考一下为什么获取缓存要加锁的方式?
  其实这个是为了防止缓存穿透的。当大量请求来获取缓存中没有对应数据的时候可能发生缓存击穿。这种时候加上锁就可以防止这种问题的产生。
  CacheKey : 这个类重点是看一下重写的 hash和equal方法 public class CacheKey implements Cloneable, Serializable {    private static final long serialVersionUID = 1146682552656046210L;    public static final CacheKey NULL_CACHE_KEY = new CacheKey() {      @Override     public void update(Object object) {       throw new CacheException("Not allowed to update a null cache key instance.");     }      @Override     public void updateAll(Object[] objects) {       throw new CacheException("Not allowed to update a null cache key instance.");     }   };    private static final int DEFAULT_MULTIPLIER = 37;   private static final int DEFAULT_HASHCODE = 17;    // 参与hash计算的乘数   private final int multiplier;   // CacheKey的hash值,在update函数中实时运算出来的   private int hashcode;   // 校验和,hash值的和   private long checksum;   // updateList的中元素个数   private int count;   // 8/21/2017 - Sonarlint flags this as needing to be marked transient. While true if content is not serializable, this   // is not always true and thus should not be marked transient.    private List updateList;    public CacheKey() {     this.hashcode = DEFAULT_HASHCODE;     this.multiplier = DEFAULT_MULTIPLIER;     this.count = 0;     this.updateList = new ArrayList<>();   }    public CacheKey(Object[] objects) {     this();     updateAll(objects);   }    public int getUpdateCount() {     return updateList.size();   }    public void update(Object object) {     // object的基本hash值     int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);      // 更新 count和checksum     count++;     checksum += baseHashCode;     baseHashCode *= count;      hashcode = multiplier * hashcode + baseHashCode;     // 将对象添加到updateList中     updateList.add(object);   }    public void updateAll(Object[] objects) {     for (Object o : objects) {       update(o);     }   }    /**    *  重写的eq方法    * @param object    * @return    */   @Override   public boolean equals(Object object) {     // 比较是不是同一个对象     if (this == object) {       return true;     }     // 是否类型相同     if (!(object instanceof CacheKey)) {       return false;     }      final CacheKey cacheKey = (CacheKey) object;     // hashcode是否相同     if (hashcode != cacheKey.hashcode) {       return false;     }     // checksum是否相同     if (checksum != cacheKey.checksum) {       return false;     }      // count是否相同     if (count != cacheKey.count) {       return false;     }      // 以上都不相同,才按顺序比较updateList中元素的hash值是否一致     for (int i = 0; i < updateList.size(); i++) {       Object thisObject = updateList.get(i);       Object thatObject = cacheKey.updateList.get(i);       if (!ArrayUtil.equals(thisObject, thatObject)) {         return false;       }     }     return true;   }    @Override   public int hashCode() {     return hashcode;   }    @Override   public String toString() {     StringJoiner returnValue = new StringJoiner(":");     returnValue.add(String.valueOf(hashcode));     returnValue.add(String.valueOf(checksum));     updateList.stream().map(ArrayUtil::toString).forEach(returnValue::add);     return returnValue.toString();   }    @Override   public CacheKey clone() throws CloneNotSupportedException {     CacheKey clonedCacheKey = (CacheKey) super.clone();     clonedCacheKey.updateList = new ArrayList<>(updateList);     return clonedCacheKey;   }  }
  封面侵权删
windows10必备的软件有哪些?一冰点文库下载器。虽然迫于各种压力冰点的网站和软件已经停止了更新维护和下载,但是江湖上流传的冰点文库下载器依然好使。冰点文库下载器仅仅5。9MB,免安装,无广告。它可以自由下载百度装激光雷达的车要卖多少钱?华为要卖40万,小鹏只卖20万关注自动驾驶技术的人,一定会清楚,目前在自动驾驶上有两大派系,一派是视觉派,以特斯拉百度为代表。一派是激光雷达派,以华为小鹏为代表。特斯拉之所以不用激光雷达,有两个方面的原因,一方华为撤离加拿大后,任正非再次放大招,美媒谷歌将不是华为对手点击关注,每天精彩不断!导读华为撤离加拿大后,任正非再次放大招,美媒谷歌将不是华为对手!华为公司作为中国第一大的民营科技企业,在国内市场上,说起华为公司的名字,几乎无人不知无人不晓禁令重压下,共享电单车难以踏进一线城市在共享单车发展正盛时代,速度更快骑行距离更远的电单车进入大家的视野,并且陆陆续续投放各个城市。那么比共享单车更快省力骑行距离更远的电单车,为什么迟迟没有入驻一线城市?共享单车的优势L2级就能实现自动泊车,3D打印车身,原来未来汽车长这样子在日前开幕的慕尼黑车展上,奔驰宝马大众等德系豪强展出了不少的重磅新能源车型,为新能源汽车市场指引了新的发展方向。实际上,相较新车的外观设计,搭载于车型上的前瞻性技术同样值得关注。当活泼可爱惹人爱,奇瑞QQ冰淇淋亮相奇瑞宣布与阿里云达成战略合作,并推出奇瑞iCar生态品牌,该品牌旗下首个产品序列定名为QQ,首款车型命名为QQ冰淇淋,定位为A0级纯电动车。据官方公布的信息,其盲订订单也已经突破了字节跳动布局元宇宙,是一场豪赌,还是乘上新的风口?不久前,字节跳动收购Pico的消息被官方盖章确认,直接点燃了市场情绪,沉寂已久的VR版块迎来了大涨。从腾讯提出的全真互联网,到各大巨头紧锣密鼓布局元宇宙可以看出,新的航海时代即将到人类现在是不是宇宙中最高等的文明存在?人类现在是不是宇宙中最高等的文明存在?一部分人认为,人类发现不了外星文明,说明没有外星人,人类就是宇宙中最高的文明。还有部分人认为宇宙这么大,人类发现不了外星文明,不等于外星文明也来了,机器人时代!机器取代人之后,我们该去哪里?你是否想象过,未来这样的场景。你坐着无人驾驶的汽车,在路上就可以把家里的空调打开,热水器调好。然后,你再通知让机器人管家准备好自己最爱吃的麻辣烫。你到达自己家楼下。走进那栋可以抗住买国行or美版日版?苹果iPhone13系列全球价格对比毫无悬念地,今天(北京时间9月15日)凌晨,苹果发布了全新的iPhone13系列手机,包括了iPhone13miniiPhone13iPhone13Pro以及iPhone13Pro超200亿负债,12项被执行人信息,贾跃亭回国时间又要推迟了?面对资产一次次被摆在拍卖网的货架上,不知身在国外的贾跃亭作何感想?9月14日,据天眼查风险信息,贾跃亭又新增一项被执行人信息,执行法院为深圳市中级人民法院,执行标的为4。56亿元,
百度系迎来收获期?极米科技业绩增长解禁市值近百亿元这家科创板公司即将迎来百亿市值解禁。2月22日,极米科技披露公告显示,本次限售股上市流通数量为2137。18万股,占公司总股本数的比例为42。74,限售股上市流通日期为2022年3iQOO拿出三周年诚意,发布最贵手机,普通用户能买得起么?说iQOO9Pro是最贵的iQOO手机我倒不怎么认同,毕竟这是iQOO家族的第四款Pro产品,价格比起之前几代并没有明显提升。而大家之所以反应这么激烈最大的原因还是发布时间之前的i小鹏腰斩蔚来垫底,2月难倒新势力深途(shentucar)原创作者黎明编辑魏佳蔚小理的2月销量,比往常来的更晚一些,也要更少一些。3月1日,直到下午港股收盘,蔚来理想小鹏才集中在这个时候,发布了2月的成绩单蔚来6更智能便捷的通信体验要来了?OPPO发布零功耗通信白皮书不知不觉中,5G已经慢慢融入了各行各业,5G通信时代的大门已经打开。在推动5G加速普及的道路上,各大运营商和手机厂商所做的努力功不可没。以OPPO为例,早在2015年OPPO就已经电话费不足,电话打不了,骗子为什么能在网上长久又明目张胆骗人?如果电话费不足电话当然打不了啦,但把电话费交上电话就打得了了啊,交电话费这种事可以线上交的,连三分钟都不用,再说了不想手机话费不足多交点话费就好了,虽然骗子的话费要多少我不是清楚,三星Exynos2200正式发布首个硬件级光追来了此前跳票许久的三星Exynos2200曾多次传出被取消的消息,就在一众星粉们失望之际,三星却又在1月18日上午突然发布了采用4nm极紫外光刻工艺的Exynos2200处理器。三星表刀法精湛卡位精准,AMDRX6500XT显卡解读一直以来,显卡市场的竞争都非常激烈,从标准的对位PK,到精妙的错位竞争,AMD和英伟达都是各显神通。通过对核心显存接口等规格的精细调节,实现对同档次竞品的压制,可谓是刀法精湛。在今既能提高电脑流畅,又能防止电脑桌面材料丢失不妨学一下这两招招一,为什么电脑总是出现有时候的卡顿,有时候顺畅的情况,现在教你一招,让你的电脑性能瞬间提高流畅。首先点一下此电脑,鼠标右键打开属性,点开进入高级系统设置,再看到性能点设置选择调整地平线8号Power登机箱绅士范颜值,大容量收纳作为一个上班族,平时也免不了经常去出差,带上各种工作需要的档案和自己喜欢的电子产品去往一个陌生的城市,对于旅行箱的需求还是比较高的。在我看来,旅行箱能够反映出一个人的气质,在机场车风冷和水冷各有优势!九州风神AK620上手体验在DIY主机上面,CPU散热器是对平台性能影响很大的一个组件,不仅选择的时候要为CPU和机箱量体裁衣,而且用过一段时间也要做些清洁维护,这样才能确保CPU的性能表现。在散热器的选择不仅干好本职,须眉剃须刀新玩法,居然可以当充电宝手电和风扇剃胡须是每个男人都要干的事,毕竟几天不剃胡须,胡子渣又长长了,作为须眉(SMATE)的粉丝,须眉剃须刀T6pro推出后,小编及时入手,想抢先体验一把这剃须刀的新玩法。从产品的功能介