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

重新认识下JVM级别的本地缓存框架GuavaCache优秀从何而来

  大家好,又见面了。
  本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面。如果感兴趣,欢迎关注以获取后续更新。
  不知不觉,这已经是《深入理解缓存原理与实战设计》系列专栏的第6篇文章了。经过前面5篇文章的铺垫,我们系统且全面地介绍了缓存相关的概念与典型问题,也手动实操了如何构建一个本地最简版本的通用缓存框架,还对JAVA主流的本地缓存规范进行了解读。
  秉持着不重复造轮子的理念,本篇文章中,我们就来一起深入剖析JAVA本地缓存的优秀"  轮子  " —— 来自 Google 家族的 Guava Cache  。聊一聊其实现机制 、看一看如何使用 。
  Guava Cache初识
  Guava  是Google提供的一套JAVA的工具包,而 Guava Cache  则是该工具包中提供的一套完善的JVM级别 的高并发缓存框架。其实现机制类似ConcurrentHashMap,但是进行了众多的封装与能力扩展。作为JVM级别的本地缓存框架,Guava Cache  具备缓存框架该有的众多基础特性。当然,Guava Cache能从众多本地缓存类产品中脱颖而出,除了具备上述基础缓存特性外,还有众多贴心的能力增强,绝对算得上是工具包届的超级暖男 !为什么这么说呢?我们一起看下Guava Cache的能力介绍,应该可以有所体会。
  支持缓存记录的过期设定
  作为一个合格的缓存容器,支持缓存记录过期是一个基础能力。  Guava Cache  不但支持设定过期时间,还支持选择是根据插入时间  进行过期处理(创建过期 )、或者是根据最后访问时间  进行过期处理(访问过期 )。
  过期策略
  具体说明
  创建过期
  基于缓存记录的插入时间判断。比如设定10分钟过期,则记录加入缓存之后,  不管有没有访问  ,10分钟时间到则
  访问过期
  基于最后一次的访问时间来判断是否过期。比如设定10分钟过期,如果缓存记录被访问到,则以最后一次访问时间重新计时;只有连续10分钟没有被访问的时候才会过期,否则将一直存在缓存中不会被过期。
  实际使用的时候,可以在创建缓存容器的时候指定过期策略即可:  基于  创建时间  过期 public Cache createUserCache() {     return CacheBuilder.newBuilder()         .expireAfterWrite(30L, TimeUnit.MINUTES)         .build(); } 基于  访问时间  过期 public Cache createUserCache() {     return CacheBuilder.newBuilder()         .expireAfterAccess(30L, TimeUnit.MINUTES)         .build(); }
  是不是很方便?
  支持缓存容量限制与不同淘汰策略
  作为内存型缓存,必须要防止出现内存溢出的风险。Guava Cache支持设定缓存容器的最大存储上限,并支持根据缓存记录  条数  或者基于每条缓存记录的权重  (后面会具体介绍)进行判断是否达到容量阈值。
  当容量触达阈值后,支持根据  FIFO + LRU  策略实施具体淘汰处理以腾出位置给新的记录使用。
  淘汰策略
  具体说明
  FIFO
  根据缓存记录写入的顺序,先写入的先淘汰
  LRU
  根据访问顺序,淘汰最久没有访问的记录
  实际使用的时候,同样是在创建缓存容器的时候指定容量上限与淘汰策略,这样就可以放心大胆地使用而不用担心内存溢出问题咯。  限制缓存  记录条数  public Cache createUserCache() {     return CacheBuilder.newBuilder()             .maximumSize(10000L)             .build(); } 限制缓存  记录权重  public Cache createUserCache() {     return CacheBuilder.newBuilder()             .maximumWeight(10000L)             .weigher((key, value) -> (int) Math.ceil(instrumentation.getObjectSize(value) / 1024L))             .build();     }
  这里需要注意:按照权重进行限制缓存容量的时候必须要指定  weighter  属性才可以生效。上面代码中我们通过计算value  对象的字节数(byte)来计算其权重信息,每1kb的字节数作为1个权重,整个缓存容器的总权重限制为1w,这样就可以实现将缓存内存占用控制在10000*1k≈10M  左右。
  有没有很省心?
  支持集成数据源能力
  在前面文章中,我们有介绍过缓存的  三种模型  ,分别是 旁路型  、穿透型  、异步型  。Guava Cache作为一个封装好的缓存框架,是一个典型的穿透型缓存 。正常业务使用缓存时通常会使用旁路型缓存,即先去缓存中尝试查询获取数据,如果获取不到则会从数据库中进行查询并加入到缓存中;而为了简化业务端使用复杂度,Guava Cache支持集成数据源,业务层面调用接口查询缓存数据的时候,如果缓存数据不存在,则会自动去数据源中进行数据获取并加入缓存中。public User findUser(Cache cache, String userId) {     try {         return cache.get(userId, () -> {             System.out.println(userId + "用户缓存不存在,尝试回源查找并回填...");             return userDao.getUser(userId);         });     } catch (ExecutionException e) {         e.printStackTrace();     }     return null; }
  实际使用的时候如果查询的用户不存在,则会自动去回源查找并写入缓存里,再次获取的时候便可以从缓存直接获取:
  上面的方法里,是通过在get方法里传入  Callable  实现的方式指定回源获取数据的方式,来实现缓存不存在情况的自动数据拉取与回填到缓存中的。实际使用的时候,除了Callable方式,还有一种CacheLoader  的模式,也可以实现这一效果。
  需要我们在创建缓存容器的时候声明容器为  LoadingCache  类型(下面的章节中有介绍),并且指定 CacheLoader  处理逻辑:public LoadingCache createUserCache() {     return CacheBuilder.newBuilder()             .build(new CacheLoader() {                 @Override                 public User load(String key) throws Exception {                     System.out.println(key + "用户缓存不存在,尝试CacheLoader回源查找并回填...");                     return userDao.getUser(key);                 }             });     }
  这样,获取不到数据的时候,也会自动回源查询并填充。比如我们执行如下调用逻辑:      public static void main(String[] args) {         CacheService cacheService = new CacheService();         LoadingCache cache = cacheService.createUserCache();         try {             System.out.println(cache.get("123"));             System.out.println(cache.get("124"));             System.out.println(cache.get("123"));         } catch (Exception e) {             e.printStackTrace();         }     }
  执行结果如下:  123用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=123, userName=铁柱, department=研发部) 124用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=124, userName=翠花, department=测试部) User(userId=123, userName=铁柱, department=研发部)
  两种方式都可以实现这一效果,实际可以根据需要与场景选择合适的方式。
  当然,有些时候,可能也会涉及到  CacheLoader  与Callable  两种方式结合使用的场景,这种情况下优先 会执行Callable提供的逻辑,Callable缺失的场景会使用CacheLoader提供的逻辑。public static void main(String[] args) {     CacheService cacheService = new CacheService();     LoadingCache cache = cacheService.createUserCache();     try {         System.out.println(cache.get("123", () -> new User("xxx")));         System.out.println(cache.get("124"));         System.out.println(cache.get("123"));     } catch (Exception e) {         e.printStackTrace();     } }
  执行后,可以看出Callable逻辑被  优先执行  ,而CacheLoader作为  兜底策略  存在:  User(userId=xxx, userName=null, department=null) 124用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=124, userName=翠花, department=测试部) User(userId=xxx, userName=null, department=null)
  支持更新锁定能力
  这个是与上面数据源集成一起的辅助增强能力。在高并发场景下,如果某个key值没有命中缓存,大量的请求同步打到下游模块处理的时候,很容易造成  缓存击穿  问题。
  为了防止缓存击穿问题,可以通过  加锁  的方式来规避。当缓存不可用时,仅 持锁的线程  负责从数据库中查询数据并写入缓存中,其余请求重试时先尝试从缓存中获取数据,避免所有的并发请求全部同时打到数据库上。
  作为穿透型缓存的保护策略之一,  Guava Cache  自带了  并发锁定  机制,同一时刻仅允许一个请求去回源获取数据并回填到缓存中,而其余请求则阻塞等待,不会造成数据源的压力过大。
  有没有被暖心到?
  提供了缓存相关的一些监控统计
  引入缓存的一个初衷是希望缓存能够提升系统的处理性能,而有限缓存容量中仅存储部分数据的时候,我们会希望存储的有限数据可以尽可能的覆盖并抗住大部分的请求流量,所以对缓存的  命中率  会非常关注。
  Guava Cache深知这一点,所以提供了  stat  统计日志,支持查看缓存数据的加载或者命中情况统计。我们可以基于命中情况,不断地去优化代码中缓存的数据策略,以发挥出缓存的最大价值。
  Guava Cache的统计信息封装为  CacheStats  对象进行承载,主要包含一下几个关键指标项:
  指标
  含义说明
  hitCount
  命中缓存次数
  missCount
  没有命中缓存次数(查询的时候内存中没有)
  loadSuccessCount
  回源加载的时候加载成功次数
  loadExceptionCount
  回源加载但是加载失败的次数
  totalLoadTime
  回源加载操作总耗时
  evictionCount
  删除记录的次数
  缓存容器创建的时候,可以通过  recordStats()  开启缓存行为的统计记录:    public static void main(String[] args) {         LoadingCache cache = CacheBuilder.newBuilder()                 .recordStats()                 .build(new CacheLoader() {                     @Override                     public User load(String key) throws Exception {                         System.out.println(key + "用户缓存不存在,尝试CacheLoader回源查找并回填...");                         User user = userDao.getUser(key);                         if (user == null) {                             System.out.println(key + "用户不存在");                         }                         return user;                     }                 });          try {             System.out.println(cache.get("123");             System.out.println(cache.get("124"));             System.out.println(cache.get("123"));             System.out.println(cache.get("126"));          } catch (Exception e) {         } finally {             CacheStats stats = cache.stats();             System.out.println(stats);         }     }
  上述代码执行之后结果输出如下:  123用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=123, userName=铁柱, department=研发部) 124用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=124, userName=翠花, department=测试部) User(userId=123, userName=铁柱, department=研发部) 126用户缓存不存在,尝试CacheLoader回源查找并回填... 126用户不存在 CacheStats{hitCount=1, missCount=3, loadSuccessCount=2, loadExceptionCount=1, totalLoadTime=1972799, evictionCount=0}
  可以看出,一共执行了4次请求,其中1次命中,3次回源处理,2次回源加载成功,1次回源没找到数据,与打印出来的  CacheStats  统计结果完全吻合。
  有着上述能力的加持,前面将Guava Cache称作"  暖男  "不过分吧?
  Guava Cache适用场景
  在本系列专栏的第一篇文章《聊一聊作为高并发系统基石之一的缓存,会用很简单,用好才是技术活》中,我们在缓存的一步步演进介绍中提过本地缓存与集中式缓存的区别,也聊了各自的优缺点。
  作为一款纯粹的本地缓存框架,Guava Cache具备本地缓存该有的  优势  ,也无可避免的存在着本地缓存的 弊端  。
  维度
  简要概述
  优势
  基于  空间换时间  的策略,利用内存的高速处理效率,提升机器的处理性能,减少大量对外的 IO请求 交互,比如读取DB、请求外部网络、读取本地磁盘数据等等操作。
  弊端
  整体  容量受限  ,可能对本机内存造成压力。此外,对于分布式多节点集群部署的场景,缓存更新场景会出现 缓存漂移  问题,导致各个节点之间的缓存 数据不一致 。
  鉴于上述优劣综合判断,可以大致圈定  Guava Cache  的实际适用场合:数据  读多写少  且对 一致性要求不高  的场景
  这类场景中,会将数据缓存到本地内存中,采用定时触发(或者事件推送)的策略重新加载到内存中。这样业务处理逻辑直接从内存读取需要的数据,修改系统配置项之后,需要等待一定的时间后方可生效。
  很多的配置中心采用的都是这个缓存策略。统一配置中心中管理配置数据,然后各个业务节点会从统一配置中心拉取配置并存储在自己本地的内存中然后使用本地内存中的数据。这样可以有效规避配置中心的单点故障问题,降低了配置中心的请求压力,也提升了业务节点自身的业务处理性能(减少了与配置中心之间的网络交互请求)。  对  性能  要求 极其严苛  的场景
  对于分布式系统而言,集中式缓存是一个常规场景中很好的选项。但是对于一些超大并发量且读性能要求严苛的系统而言,一个请求流程中需要频繁的去与Redis交互,其网络开销也是不可忍受的。所以可以采用将数据本机内存缓存的方式,分散redis的压力,降低对外请求交互的次数,提升接口响应速度。  简单的本地数据缓存,作为  HashMap/ConcurrentHashMap  的替代品
  这种场景也很常见,我们在项目中经常会遇到一些数据的需要临时缓存一下,为了方便很多时候直接使用的  HashMap  或者ConcurrentHashMap  来实现。而Guava Cache聚焦缓存场景做了很多额外的功能增强(比如数据过期能力支持、容量上限约束等),可以完美替换掉HashMap/ConcurrentHashMap,更适合缓存场景使用。
  Guava Cache使用引入依赖
  使用Guava Cache,首先需要引入对应的依赖包。对于Maven项目,可以在  pom.xml  中添加对应的依赖声明即可:     com.google.guava     guava     31.1-jre 
  这样,就完成了依赖引入。
  容器创建 —— CacheBuilder
  具体使用前首先面临的就是如何创建Guava Cache实例。可以借助  CacheBuilder  以一种优雅的方式来构建出合乎我们诉求的Cache实例。
  对  CacheBuilder  中常见的属性方法,归纳说明如下:
  方法
  含义说明
  newBuilder
  构造出一个Builder实例类
  initialCapacity
  待创建的缓存容器的初始容量大小(记录  条数  )
  maximumSize
  指定此缓存容器的最大容量(最大缓存记录  条数  )
  maximumWeight
  指定此缓存容器的最大容量(最大  比重  值),需结合 weighter  方可体现出效果
  expireAfterWrite
  设定过期策略,按照数据  写入时间  进行计算
  expireAfterAccess
  设定过期策略,按照数据最后  访问时间  来计算
  weighter
  入参为一个函数式接口,用于指定每条存入的缓存数据的权重占比情况。这个需要与  maximumWeight  结合使用
  refreshAfterWrite
  缓存写入到缓存之后
  concurrencyLevel
  用于控制缓存的并发处理能力,同时支持多少个线程  并发写入  操作
  recordStats
  设定开启此容器的数据加载与缓存命中情况统计
  基于  CacheBuilder  及其提供的各种方法,我们可以轻松的进行缓存容器的构建、并指定容器的各种约束条件。
  比如下面这样:  public LoadingCache createUserCache() {     return CacheBuilder.newBuilder()             .initialCapacity(1000) // 初始容量             .maximumSize(10000L)   // 设定最大容量             .expireAfterWrite(30L, TimeUnit.MINUTES) // 设定写入过期时间             .concurrencyLevel(8)  // 设置最大并发写操作线程数             .refreshAfterWrite(1L, TimeUnit.MINUTES) // 设定自动刷新数据时间             .recordStats() // 开启缓存执行情况统计             .build(new CacheLoader() {                 @Override                 public User load(String key) throws Exception {                     return userDao.getUser(key);                 }             }); }
  业务层使用
  Guava Cache容器对象创建完成后,可以基于其提供的对外接口完成相关缓存的具体操作。首先可以了解下Cache提供的对外操作接口:
  对关键接口的含义梳理归纳如下:
  接口名称
  具体说明
  get
  查询指定key对应的value值,如果缓存中没匹配,则基于给定的  Callable  逻辑去获取数据回填缓存中并返回
  getIfPresent
  如果缓存中存在指定的key值,则返回对应的value值,否则返回null(此方法  不会触发  自动回源与回填操作)
  getAllPresent
  针对传入的key列表,返回缓存中存在的对应value值列表(  不会触发  自动回源与回填操作)
  put
  往缓存中添加key-value键值对
  putAll
  批量往缓存中添加key-value键值对
  invalidate
  从缓存中删除指定的记录
  invalidateAll
  从缓存中批量删除指定记录,如果无参数,则清空所有缓存
  size
  获取缓存容器中的总记录数
  stats
  获取缓存容器当前的统计数据
  asMap
  将缓存中的数据转换为  ConcurrentHashMap  格式返回
  cleanUp
  清理所有的已过期的数据
  在项目中,可以基于上述接口,实现各种缓存操作功能。  public static void main(String[] args) {     CacheService cacheService = new CacheService();     LoadingCache cache = cacheService.createUserCache6();     cache.put("122", new User("122"));     cache.put("122", new User("122"));     System.out.println("put操作后查询:" + cache.getIfPresent("122"));     cache.invalidate("122");     System.out.println("invalidate操作后查询:" + cache.getIfPresent("122"));     System.out.println(cache.stats()); }
  执行后,结果如下:  put操作后查询:User(userId=122, userName=null, department=null) invalidate操作后查询:null CacheStats{hitCount=1, missCount=1, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=0}
  当然,上述示例代码中这种使用方式有个明显的弊端就是业务层面对Guava Cache的  私有API  依赖过深 ,后续如果需要替换Cache组件的时候会比较痛苦,需要对业务调用的地方进行大改。所以真正项目里面,最好还是对其适当封装,以实现业务层面的解耦 。如果你的项目是使用Spring框架,也可以基于Spring Cache  统一规范来集成并使用Guava Cache,降低对业务逻辑的侵入 。
  小结回顾
  好啦,关于Guava Cache的功能与关键特性介绍,以及项目中具体的集成与使用方法,就介绍到这里了。总结一下,Guava Cache其实就是一个增强版的大号ConcurrentHashMap,在保证线程安全的情况下,增加了缓存必备的数据过期、容量限制、回源策略等能力,既保证了本身的精简,又使得整体能力足以满足大部分本地缓存场景的使用诉求。也正是由于这些原因,Guava Cache在JAVA领域广受好评,使用范围非常的广泛。
  下一篇文章中,我们将继续对Guava Cache展开讨论,跳出使用层面,剖析其内部核心实现逻辑。如果有兴趣,欢迎关注后续文章的更新。
  那么,关于本文中提及的内容,你是否有自己的一些想法与见解呢?欢迎评论区一起交流下,期待和各位小伙伴们一起切磋、共同成长。
  补充说明1   : 本文属于《深入理解缓存原理与实战设计》系列专栏的内容之一。该专栏围绕缓存这个宏大命题进行展开阐述,全方位、系统性地深度剖析各种缓存实现策略与原理、以及缓存的各种用法、各种问题应对策略,并一起探讨下缓存设计的哲学。
  如果有兴趣,也欢迎关注此专栏。
  补充说明2   : 关于本文中涉及的  演示代码  的完整示例,我已经整理并提交到github中,如果您有需要,可以自取:https://github.com/veezean/JavaBasicSkills
  我是悟道,聊技术、又不仅仅聊技术~
  如果觉得有用,请  点赞 + 关注  让我感受到您的支持。也可以关注下我的公众号【架构悟道】,获取更及时的更新。
  期待与你一起探讨,一起成长为更好的自己。

58组合参与合练已具备出场条件,巴尔加斯要帮海港夺冠海港在世纪公园继续训练,武磊巴尔加斯出现在训练队伍之中,官方透露球队将在本周日前往郑州,备战下周二与河南嵩山龙门的比赛。根据记者刘闻超透露,这两人已具备一定出场条件。中秋节巴尔加斯围棋王子常昊娶大他8岁的二婚棋手张璇为妻,现在怎样了?头条创作挑战赛点击关注,每天都有名人故事感动您!常昊夫妇与女儿常昊是我国围棋新一代领军人物,夺得过第5届应氏杯第11届三星杯第7届春兰杯冠军,被媒体和棋迷誉为围棋王子。当前常昊是我俄军真的很强?2018军演,我军2个营为何一天就全歼俄军1个摩步团俄军很强这个概念,早就被大多数人视为不可动摇的真理了。无论是我们这种普通人还是军迷,甚至是专业的分析人士,就认同这个说法。但是,俄军常规军事实力真的很强吗?兰德公司建议对抗俄军最重高三语文必备知识和关键能力(语病部分)一搭配不当1。主谓搭配不当(2016年高考全国新课标卷)近日刚刚建成的西红门创业大街和青年创新创业大赛同步启动,绿色设计和互联网农业设计是本次赛事的两大主题。设误方式多主一谓语法储推特内部被曝潜入中国特工,前高管向美国国会举报核心信息危险所谓的中国特工又火了,这次被曝遭潜入的公司是美国通讯龙头企业推特。爆料者还提到了FBI,称FBI对中国特工一事知情。据环球网报道,爆料者是推特公司的前安全主管佩特扎特科。(佩特扎特总裁抛售套现,浙江理想申请注销!理想法务部追究造谣者法律责任本田将停产燃油摩托车百万保时捷撞后起火1人被烧身亡?中国汽车首次登榜莫斯科畅销车榜首关闭部分店面,特斯拉或调整零售策略斯堪尼亚与壳牌签署战略合作意向书关键词理想本田保时捷特斯拉壳牌国乒2对女双1对男双全输!徐海东吴洋晨进混双四强,迎中韩对决9月16日,2022年WTT常规挑战赛哈萨克斯坦阿拉木图站继续进行,国乒在男双与女双赛场均输球,三对组合全出局,无缘男女双半决赛混双徐海东吴洋晨顺利晋级四强,半决赛将迎中韩对决。在懵了!又是找大跌原因的一天,4200股下跌!刚刚,外交部宣布制裁!我们跑路了抱歉,便宜500元预售iPhone14,卷款跑了中国基金报泰勒兄弟姐妹们啊,过完疯狂星期四,周五A股又疯狂了一天,三大指数均跌超2,4000多只个股下跌。泰勒哥这又得含泪找原因,天天这么找,就快麻了!不过好消息是收盘止跌了,周末沃尔沃XC607。1秒破百,油耗比X3还低?全时四驱8AT,拿捏了在40万左右的豪华品牌SUV车型中,沃尔沃XC60算的上是最特立独行的一个,简约的设计乍一看并不张扬,但当你细细体验下来之后,你才会发现它所坚守的豪华态度,我们本篇文章的主角便是前37岁实现财务自由,冲上热搜!雷军造车到底能不能成功?十八九岁,一本硅谷之火点燃了雷军,他希望创办一家技术公司,从而影响世界。站在五十二岁的角度看,一个在八十年代,大四就敢于创业的青年,就像一团别致的火,人生总不会特别黯淡。其实,捋一渤海大学在2022年竞技世界杯中国大学生计算机博弈大赛中再创佳绩近日,2022年竞技世界杯中国大学生计算机博弈大赛暨第十六届中国计算机博弈锦标赛圆满落幕。渤海大学师生积极备赛,通过小组循环决赛PK专家评审等环节激烈角逐,再创佳绩,获得一等奖2项
俄罗斯将在2024年后退出国际空间站俄罗斯太空总署(Roscosmos)负责人周二宣布,俄罗斯计划在2024年后退出国际空间站。根据他与俄罗斯总统弗拉基米尔普京会晤的记录,尤里鲍里索夫说我们将履行对我们的合作伙伴的所15时!中国男足冲东亚杯首胜,洋帅或变阵激活戴伟浚,央视直播7月27日15时,东亚杯继续进行,中国男足对阵中国香港。本场比赛,中国男足只要打平就可以确保排名第3,不过对于扬科维奇和国足队员们来说,这场比赛的目标只有一个,那就是赢球。从防守到苹果应用内藏色情App,被色情问题困扰十多年,都是抽佣惹的祸?苹果应用商店,被曝内藏大量色情App,本来只有一些老司机知道,现在众人皆知。目前苹果只表示了震惊,而大部分被曝光的软件依然可以下载,被很多人批评纵容违规行为,没有责任感。苹果应用商医保跨省异地就医直接结算,最新通知来了国家医保局会同财政部今天共同印发了关于进一步做好基本医疗保险跨省异地就医直接结算工作的通知。通知要求,各地医保部门要及时调整与本通知不相符的政策措施,确保2022年12月底前同国家湖南这所本科大学招生遇冷,缺额近千人,为何被考生抛弃湖南这所本科大学招生遇冷,缺额近千人,为何被考生抛弃?湖南是我国的高考大省,据潇湘晨报报道2022年湖南高考报名人数65。5万。湖南基础教育在全国来说是非常不错的,迄今为止湖南学子2岁女童不慎从六楼坠落,千钧一发,市民扔掉手机徒手接住孩子7月20日,下午。马上3岁的女童从六楼坠落,让人看得心惊肉跳的。天气炎热,路上行人很少,临街店铺都关了门窗,没有人发现这场意外。马路对面是银行员工,沈东,陆晓婷,发现孩子后,迅速跑吴啊萍受审画面曝光,网友更愤怒了7月24日,江苏南京,南京发布公布玄奘寺供奉侵华日军战犯牌位事件通报,供奉牌位者吴啊萍自述,其在了解到侵华日军战犯的暴行后,产生心理阴影,长期被噩梦缠绕,于是产生了通过供奉5名侵华女神就能俘获男人的心?郭碧婷王冰冰都没做到副标题向佐徐嘉余被爆出轨,网友那可是郭碧婷王冰冰啊每一个人心中都有一个属于自己的女神,若女神如愿成为你的女友妻子,你会对她矢志不渝爱心不变吗?点点君觉得,大部分人都会做到这一点,但拼命三娘左小青的桃色往事,以及靠美色征服的7个男人如果不是她,清白了一生的陈道明也不会自此染上污点。谈起当年轰动一时的陈左恋,陈道明的忠实粉丝们依然义愤填膺,认为左小青玷污了他们的偶像。在中国影视圈,提起陈道明是令人肃然起敬。终其神回复网友骂人能斯文到什么程度?太有学问了,抓紧抄下来树大家看都看到了我可是一动也没动啊狗子天气太热,终于找到个乘凉的好地方有个二货朋友究竟是一种什么体验这样的作文你给打几分呢还好反应快要不然就要请全村人吃席了鱼我也不知道他为什么要这辽宁大学回应教师性骚扰称已免职,网友老师选择应该优先道德辽大骚扰学生辅导员被免职所谓钓鱼,肯定不会是拿着鱼竿前往哪哪哪,然后一坐坐很长时间,这里的钓鱼更是为了求取某些东西,然后一步一步地设套引诱对面朝着自己布下的陷阱,最后为自己所用。事