一种通用缓存的方法

文档序号:6560791阅读:243来源:国知局
专利名称:一种通用缓存的方法
技术领域
本发明涉及一种数据处理方法,特别涉及一种数据的缓存方法。
技术背景目前在业务软件系统应用中,对于系统处理性能要求越来越高,所以应该 避免频繁的进行数据库操作和文件读写。为解决数据读取低效的问题必然会考 虑到使用缓存技术。缓存就是将一定的数据存放在内存中,当系统需要访问此 数据时,将可以直接从内存中读取,而减免了数据库操作和文件读写的耗时。 在现实环境下,对于大数据量,系统不可能将所有数据缓存到内存中,所以需 要使用一定的策略进行缓存项的淘汰,并且缓存需要在它的缓存项发生变化的 时候对其进行更新处理。目前现有的缓存系统大多采用LRU(最近最少使用)算法,LRU算法是一 种比较简单的淘汰选择算法,它不能真实的反映缓存中内容的使用情况。目前现有的一些缓存系统为了实现简单,而没有提供缓存同步功能,这将 导致缓存的数据和真实数据的偏差。有一些缓存系统虽然提供了缓存同步功 能,但是因为需要消耗大量的系统资源,导致缓存同步代价过大。发明内容本发明所要解决的技术问题在于提出一种通用缓存的方法,在系统对外部 数据源需要进行频繁访问时,能够有效地提高读取数据的性能。为实现上述目的,本发明提出了一种通用缓存的方法,用于获取缓存中存 储的数据,其中,包括步骤--,在缓存中设置与外部数据源连接的用于获取外部数据的接口;步骤二,将缓存分配成多个缓存段,将一个数据只存放在一个缓存段里, 设置每个缓存段的名称和数据的主健值;步骤三,当缓存系统收到数据访问请求时,根据请求访问的缓存段名称和
数据的主健值,访问对应的缓存段,并判断所述缓存段中是否已存储所请求的 数据,若已存储,则输出所请求的数据,若未存储,则通过所述接口从外部数 据源获取所请求的数据,保存所请求的数据至所述缓存段中并输出。 上述的通用缓存的方法,其特征在于,还包括当访问或者修改所述缓存段时,设置段级锁,锁定所述缓存段的步骤;和 当从所述外部数据源读取所述请求的数据时,为所述缓存段中对应的数据 设置行级锁,锁定所请求的数据的步骤。上述的通用缓存的方法,其中,所述步骤三还包括步骤31,当所述缓存段中已存储所请求的数据时,判断所述已存储的数据对应的外部数据源中的数据是否已经被更新;步骤32,若未被更新,则直接输出所述已存储的数据,若已被更新,则调用所述接口从外部数据源获取对应的数据并更新所述缓存项中存储的数据。上述的通用缓存的方法,其中,所述步骤三具体包括步骤41,根据缓存段的名称和所请求的数据的主键值,访问所述缓存项 并査找所请求的数据;步骤42,为所述缓存段添加段级锁,判断所请求的数据是否存储在所述 缓存项中,若已存储,则进入步骤43,若未存储,则进入步骤44;步骤43,判断所请求的数据对应的外部数据源中的数据是否被更新,若 未被更新,则进入步骤47,若已被更新,则进入歩骤46;步骤44,判断所请求的数据是否已被添加了行级锁,若没有被添加,则 进入步骤46,若所请求的数据已被添加了行级锁,则进入步骤45;步骤45,释放段级锁,在所述行级锁被释放后,进入步骤47;步骤46,释放所述段级锁,在所请求的数据上添加行级锁,通过所述接 口,从外部数据源获取所请求的数据,保存至所述缓存段中,然后进入步骤 47;步骤47,输出所述缓存段中存放的所请求的数据。上述的通用缓存的方法,其中,当通过所述接口从外部数据源获取所请求 的数据之后,还包括以下步骤-步骤51,对所述缓存段添加段级锁;歩骤52,判断所述缓存段是否存在足够的剩余空间存储所述通过接口获
取的数据,若存在足够的剩余空间,则进入步骤53,若不存在足够的空间,则在所述缓存段中释放出足够的空间,然后进入步骤53;步骤53,将从所述接口获取的所请求的数据更新所述缓存段,释放所述段级锁和行级锁,输出更新后所请求的数据。上述的通用缓存的方法,其中,所述步骤52中,当所述缓存段没有足够 的存储空间时,采用接触计数器法在所述缓存段中释放足够的存储空间,具体包括以下步骤步骤61,査找出所述缓存段中被访问次数最少的数据;步骤62,若被访问次数最少的数据只有一个,则从所述缓存段中删除所述数据,若被访问次数最少的数据有多个,则将所述多个数据中占用空间最大的数据删除;步骤63,判断所述缓存段中的剩余空间是否能存储所请求的数据,若能 够存储,则进入所述步骤53,若不能够存储,则返回所述步骤61。 上述的通用缓存的方法,其中,还包括根据所述缓存段中的各个数据的访问次数和大小,使用单向链表或双向链 表对所述各个数据进行排序的步骤。上述的通用缓存的方法,其中,每个数据为所述链表中的一个链表节点,所述排序的步骤具体包括以下步骤步骤81,根据所述请求的数据的主键值,査找所述链表中是否存在对应 的链表节点,若存在所述链表节点,则将所述链表节点的访问次数增加l;步骤82,判断所请求的数据的大小是否改变,若没有改变,则进入步骤 84,若所请求的数据被更新,所述数据大小的改变,则修改对应的所述链表节点大小属性,然后进入步骤84;步骤83,若所述链表中不存在所述链表节点,则根据所请求的数据的主 键值、大小和访问次数,在所述链表中创建新的链表节点,然后进入步骤84;步骤84,根据所述缓存段中各个数据的访问次数和大小,将多对应的链 表节点进行排序,将被访问次数较少的链表节电排在被访问次数较多的链表节 点的前面,在被访问次数相同的链表节点中,将数据较大的链表节点排在数据 较小的链表节点的前面。上述的通用缓存的方法,其中,将所述缓存段中的各个数据进行排序时,
还包括添加热点链表和冷点链表的步骤。 上述的通用缓存的方法,其中,还包括为所述缓存段中各个数据设置包括正常状态、更新状态或删除状态的状态 标识的步骤。上述的通用缓存的方法,其中,当所述缓存段中的数据的状态标识为更新 状态时,还包括当所述数据被访问时,通过所述接口从外部数据源获取与所述数据对应的 新数据,并更新所述缓存段的步骤;当所述缓存段中的数据的状态标识为删除状态时,还包括将通过所述接口从外部数据源获取的数据,覆盖所述处于删除状态的数据 并存储的步骤。上述的通用缓存的方法,其中,所述步骤二还包括步骤121,设置所述缓存段的最大存储空间参数和从外部数据源读取数据 的接口的实现类参数;步骤122,在缓存系统启动时,初始化缓存中各个缓存段的名称和上述设置参数。本发明基于统一 User Interface (用户调用接口 )接口的基于Touch Count (接触计数器)算法的通用缓存实现方法,具有以下有益效果1. 简单,统一的UI接口。2. 缓存分段管理,管理清晰(每段只存放各自数据,与其他段没有关系), 读取性能高(査找只会在本段,而不需要到不相关的段査找费时),灵活性高(每 个段都可以有自己特殊的获取外部数据接口实现,也可以使用同一个)3. 通用性,通过获取外部数据接口屏蔽了不同系统之间的不~-致性。4. 使用Touch Count (接触计数器)算法,而不是一般缓存使用的LRU (最近最少使用)算法。5. 对缓存项的更新,不是立即产生而是在实际产生访问请求的时候进行 更新。


图1是本发明的缓存模块处理流程图;图2是本发明中touch count (接触计数器)算法操作流程图。
具体实施方式
本发明的实施方法如下(a)在缓存系统中设置一个获取外部数据信息的接口,此接口负责当缓存中没有对应数据时,通用缓存模块会根据此接口的 实现去外部数据源获取对应数据。(b)本发明中缓存实行分段管理,每段只存放各自的数据,与其他段没 有关系,査找时只在本段不需要到不相关的缓存段査找,将缓存分成多个缓存段时,需要设置相关参数。包括以下主要参数缓存段的名称(本发明对缓存是分段管理,这样增加缓存的访问性能和灵活性);缓存段的最大存储空间;从外部数据源读取数据接口的实现类(此实现类用于从外部数据源获取相关数据到缓存系统)。(C)在系统中设置二级锁对象,分别包括 第一级段级锁,在并发访问或者并发修改缓存段时锁定该缓存段。 第二级行级锁,在缓存段从外部数据源读取数据的时候加行级锁,释放段级锁(一般情况从外部数据源读数据是比较耗时的操作),增加缓存模块的并发响应。(d)当缓存模块收到一个数据访问请求时,缓存模块根据请求中携带的缓存段的名称和数据Key值(主键值,每个数据在缓存段中都有一个唯一的 Key值,用于缓存段中快速定位和与其他数据区分)信息,到指定的缓存段去 査找数据并且添加段级锁,当所请求的数据找到的情况下如果找到并且数据对应的外部数据没有被更新,将数据返回给访问请求并 且更新数据的访问次数,释放段级锁;如果找到但是数据对应的外部数据已经被更新,缓存模块在此缓存段中释 放段级锁然后对此数据Key值加行级锁并且调用获取外部数据接口获取更新 数据,将更新数据并且更新访问次数和数据大小,释放行级锁;如果缓存段没 有足够的空间更新数据,将根据Touch Count (接触计数器)算法在缓存段中 释放足够的空间供数据更新当所请求的数据找不到的情况下如果找不到并且对应的数据Key没有加行级锁时,缓存模块在此缓存段 中为此数据Key加行级锁并且调用获取外部数据信息接口获取新数据,将新 数据加入缓存段并且更新访问次数和数据大小,释放此行级锁;如果缓存段没 有足够的空间更新数据,将根据Touch Count (接触计数器)算法释放足够的 空间供数据添加。如果找不到并且对应的数据Key己经加行级锁时,访问请求将在此行级锁上等 待,直到解锁然后从缓存段中输出所请求的数据。(e) 在系统缓存对应的数据发生更新的时候,通过缓存更新接口通知缓存 模块将对应的数据状态位标示为更新状态(数据状态包括正常状态,更新状态和 删除状态),此时并不立即更新数据,只有在该数据被再次访问时才产生实际的 更新操作。(f) 在系统缓存对应的数据被删除的时候,通过缓存删除接口通知缓存模 块将对应的数据状态标识为删除状态(数据状态包括正常状态,更新状态和删除 状态),此时并不立即删除数据,而是在添加新的数据时才覆盖此删除的数据。进一步地,上述通用缓存的实现方法具有以下特点系统对缓存的更新是 通过将数据的状态标识修改为更新状态(数据状态包括正常状态,更新状态和删 除状态)。被标示为更新状态的数据只有被再次访问的时候才会实际的更新内 容,然后将此数据的状态位修改为正常状态;如果此数据一直没有被访问内容 更新的操作就不会产生。此方法可以有效的避免不必要的实际内容更新,避免 实际内容更新时的系统消耗。1) 当数据在被访问前产生的N次更新,此方法只产生1次实际内容更新, 避免了N-1次内容更新。2) 当数据有更新,但是一直没有被访问,此方法避免了 l此内容更新。 此外,系统对缓存项中数据的更新和删除可以通过Web Service (Web服务)或者Socket (套接字)在远端操作。使用本发明所述的通用缓存系统时,需要注意要在系统启动时初始化配置
信息,包括缓存段的名称,缓存段空间的最大阀值,外部数据读取类。 下面结合附图及具体实施例对本发明进行详细说明。图1是本发明的处理流程示意图。如图1所示,用户访问缓存系统流程包 括如下步骤步骤S101:用户提供缓存段的名称(本发明的缓存系统是分段管理)和所请 求的数据Key值,访问缓存系统请求相关数据;步骤S102:缓存系统根据用户提供的缓存段的名称,为该缓存段添加段 级锁;步骤S103:缓存系统根据用户提供的所请求的数据Key值,在指定的缓 存段里査找数据,判断所请求的数据是否被缓存;步骤S104:如果步骤S103结果为数据已经被缓存,缓存系统将判断此数 据是否需要更新;步骤S105:如果步骤S103结果为数据没有被缓存,缓存系统将判断该请 求的数据在该缓存段中是否已添加了行级锁;步骤S106:如果步骤S104结果为数据不需要更新,缓存系统将该所请求 的数据输出返回给用户,流程结束;步骤S107:如果步骤S104结果为数据需要更新,缓存系统将释放步骤 S102为该缓存段添加的段级锁,然后为该数据在缓存段中添加行级锁;步骤S108:如果步骤S105结果为数据已经添加了行级锁,缓存系统将释 放步骤S102为该缓存段添加的段级锁,然后在该数据的行级锁上等待,直到 该数据的行级锁被释放;步骤S109:缓存系统通过"获取外部数据接口 "获取该数据的更新数据。步骤S110:缓存系统根据用户提供的缓存段的名称,为缓存段添加段级锁。步骤Slll:缓存系统判断该缓存段是否有足够的剩余空间存放数据。步骤S112:如果步骤Slll结果为有足够的剩余空间或者步骤S113结束 后,缓存系统将用步骤S109获取的数据更新缓存段。步骤S113:如果步骤S111结果为没有足够的剩余空间,缓存系统将使用 Touch Count (接触计数器)算法在该缓存段中释放足够的空间。步骤S114:在步骤S112结束后,缓存系统释放步骤S107为该缓存段添
加的行级锁和步骤SI 10添加的段级锁。步骤S115:在步骤S108结束后,缓存系统将该请求的数据返回给用户, 流程结束。步骤S116:在步骤S114结束后,缓存系统将此数据返回给用户,流程结束。在缓存项访问次数和缓存项本身大小发生变化时,可以使用单向链表或双向链表对缓存项进行Touch Count (接触计数器)排序。为了避免在每次缓存段空间不足时对缓存项排序造成的单点性能瓶颈,当 缓存段空间不足的情形下能快捷的获取淘汰项,本实施例中,采用双向链表对 缓存项进行Touch Count排序。在缓存项排序时添加热点链表和冷点链表,更合理的使用Touch Count(接 触计数器)算法。Touch Count (接触计数器)算法是根据数据的访问次数和数据本身的大 小来决定在缓存段超过指定大小的时候,选择需要淘汰的缓存项。具体算法是 当系统对数据访问时,数据的访问次数累加一。当缓存段的剩余空间不够存放 新创建的数据时,将根据下面的步骤淘汰数据(1) 找到访问次数最少的数据。(2) 如果找到的访问次数最少的数据只有一项,则跳转到(3),否则跳 转到(4)(3) 从缓存段中淘汰此数据,然后跳转到(5)(4) 然后在找到的多个数据中就数据内容的大小,把最大的淘汰掉,然 后跳转到(5)(5) 判断缓存段中剩余的空间是否能存放下新添加的数据。如果可以跳 转到(6),否则跳转到(l)(6) 在缓存段中添加新的数据。这里要说明的是,系统中设置的缓存大小是有限的。这主要是因为系统的 内存是有限的,稀缺的资源。如果缓存系统占用的内存过大,可能会影响其他 进程运行并且会导致系统频繁的使用虚拟缓存或swap (交换区)区,严重影 响系统性能;所以在实际的系统中,必须为缓存大小设置最大阀值。而此缓存 系统是分段管理的,所以对缓存大小的限制是分散到每个缓存段上面的,系统
对每个缓存段都使用一个长整型变量来表示此段最大允许的缓存大小,当缓存段的数据内容的大小超过缓存段的最大值时,系统会通过touch count (接触计数器)算法释放足够的空间,缓存此项内容。图2是本发明中touch count (接触计数器)算法操作流程图。如图2所 示,具体包括以下步骤步骤S201,根据请求访问的数据的内容Key获取对应的链表节点;步骤S202,判断双向链表中是否有对应的链表节点;步骤S203,如果不存在该链表节点,则根据所请求的数据Key值,内容 大小和访问次数(初始取值为1)创建该链表节点,步骤S204,如果存在该链表节点,则将该链表节点的访问次数增加1;步骤S205,步骤S203结束后,判断双向链表的链表头和链表尾是否为空, 如果不为空进入步骤S208,如果链表头或链表尾有空,则进入步骤S207;步骤S206,步骤S204结束后,判断链表节点对应的所请求的数据是否改 变(如果更新了缓存中的数据,则数据的内容大小会改变),如果改变,进入 步骤S209,如果没有改变,进入步骤S208;步骤S207,将链表头和链表尾都指向刚创建的链表节点;步骤S208,根据节点对象的访问次数和内容大小进行排序,访问次数越 小的节点越靠前,在访问次数相同的情况下,内容越大的越靠前,根据前述规 则将新创建的节点添加到链表中,然后修改前后节点和本节点的相应的属性。下面分别介绍本发明的四个实施例。第一实施例当前所请求的数据不在指定的缓存段中并且对应的缓存段有足够的剩余 空间,存放请求的数据。当系统新收到一个用户请求内容时,系统判断该数据不在指定的缓存段 中,系统为所请求的数据key分配行级锁,然后从外部数据源获取所请求的数 据,调用段级锁将此内容添加到缓存系统中对应的缓存段中,释放添加的锁, 然后返回此内容给用户。第二实施例当所请求的数据已经在缓存段中时,缓存系统获取所请求的数据并输出返 回给用户。
第三实施例当所请求的数据不在缓存段中并且该缓存段没有足够的剩余空间时,缓存系统为所请求的数据key分配行级锁,然后通过获取外部数据接口从外部数据 源获取所请求的数据,并且通过touch count (接触计数器)算法释放足够的空 间,将所请求的数据添加对应的缓存段中,然后释放所加的锁,最后输出所请 求的数据给用户。 第四实施例当缓存系统新收到一个用户的数据访问请求时,缓存系统发现所请求的数 据被添加行级锁,正在被另一个用户请求时,让用户等待,直到该行级锁被释 放。然后缓存系统唤醒用户,输出所请求的数据输出返回给用户。当然,本发明还可有其它多种实施例,在不背离本发明精神及其实质的情 况下,熟悉本领域的普通技术人员当可根据本发明做出各种相应的改变和变 形,但这些相应的改变和变形都应属于本发明所附的权利要求的保护范围。
权利要求
1.一种通用缓存的方法,用于获取缓存中存储的数据,其特征在于,包括步骤一,在缓存中设置与外部数据源连接的用于获取外部数据的接口;步骤二,将缓存分配成多个缓存段,将一个数据只存放在一个缓存段里,设置每个缓存段的名称和数据的主健值;步骤三,当缓存系统收到数据访问请求时,根据请求访问的缓存段名称和数据的主健值,访问对应的缓存段,并判断所述缓存段中是否已存储所请求的数据,若已存储,则输出所请求的数据,若未存储,则通过所述接口从外部数据源获取所请求的数据,保存所请求的数据至所述缓存段中并输出。
2. 根据权利要求1所述的通用缓存的方法,其特征在于,还包括 当访问或者修改所述缓存段时,设置段级锁,锁定所述缓存段的步骤;和 当从所述外部数据源读取所述请求的数据时,为所述缓存段中对应的数据设置行级锁,锁定所请求的数据的步骤。
3. 根据权利要求1所述的通用缓存的方法,其特征在于,所述步骤三还 包括步骤31,当所述缓存段中已存储所请求的数据时,判断所述已存储的数 据对应的外部数据源中的数据是否已经被更新;步骤32,若未被更新,则直接输出所述已存储的数据,若已被更新,则 调用所述接口从外部数据源获取对应的数据并更新所述缓存项中存储的数据。
4. 根据权利要求2或3所述的通用缓存的方法,其特征在于,所述步骤 三具体包括步骤41,根据缓存段的名称和所请求的数据的主键值,访问所述缓存项 并查找所请求的数据;步骤42,为所述缓存段添加段级锁,判断所请求的数据是否存储在所述 缓存项中,若已存储,则进入步骤43,若未存储,则进入歩骤44;步骤43,判断所请求的数据对应的外部数据源中的数据是否被更新,若 未被更新,则进入步骤47,若已被更新,则进入步骤46;步骤44,判断所请求的数据是否已被添加了行级锁,若没有被添加,则进入步骤46,若所请求的数据已被添加了行级锁,则进入步骤45;步骤45,释放段级锁,在所述行级锁被释放后,进入步骤47;步骤46,释放所述段级锁,在所请求的数据上添加行级锁,通过所述接 口,从外部数据源获取所请求的数据,保存至所述缓存段中,然后进入步骤47;步骤47,输出所述缓存段中存放的所请求的数据。
5. 根据权利要求4所述的通用缓存的方法,其特征在于,当通过所述接口从外部数据源获取所请求的数据之后,还包括以下步骤步骤51,对所述缓存段添加段级锁;步骤52,判断所述缓存段是否存在足够的剩余空间存储所述通过接口获 取的数据,若存在足够的剩余空间,则进入步骤53,若不存在足够的空间, 则在所述缓存段中释放出足够的空间,然后进入步骤53;步骤53,将从所述接口获取的所请求的数据更新所述缓存段,释放所述 段级锁和行级锁,输出更新后所请求的数据。
6. 根据权利要求5所述的通用缓存的方法,其特征在于,所述步骤52 中,当所述缓存段没有足够的存储空间时,采用接触计数器法在所述缓存段中 释放足够的存储空间,具体包括以下步骤步骤61,査找出所述缓存段中被访问次数最少的数据;步骤62,若被访问次数最少的数据只有一个,则从所述缓存段中删除所述数据,若被访问次数最少的数据有多个,则将所述多个数据中占用空间最大的数据删除;步骤63,判断所述缓存段中的剩余空间是否能存储所请求的数据,若能 够存储,则进入所述步骤53,若不能够存储,则返回所述步骤61。
7. 根据权利要求6所述的通用缓存的方法,其特征在于,还包括 根据所述缓存段中的各个数据的访问次数和大小,使用单向链表或双向链表对所述各个数据进行排序的歩骤。
8. 根据权利要求7所述的通用缓存的方法,其特征在于,每个数据为所 述链表中的一个链表节点,所述排序的步骤具体包括以下步骤步骤81,根据所述请求的数据的主键值,查找所述链表中是否存在对应 的链表节点,若存在所述链表节点,则将所述链表节点的访问次数增加l; 步骤82,判断所请求的数据的大小是否改变,若没有改变,则进入步骤 84,若所请求的数据被更新,所述数据大小的改变,则修改对应的所述链表节 点大小属性,然后进入步骤84;步骤83,若所述链表中不存在所述链表节点,则根据所请求的数据的主 键值、大小和访问次数,在所述链表中创建新的链表节点,然后进入步骤84;步骤84,根据所述缓存段中各个数据的访问次数和大小,将多对应的链 表节点进行排序,将被访问次数较少的链表节电排在被访问次数较多的链表节 点的前面,在被访问次数相同的链表节点中,将数据较大的链表节点排在数据 较小的链表节点的前面。
9. 根据权利要求7或8所述的通用缓存的方法,其特征在于,将所述缓 存段中的各个数据进行排序时,还包括添加热点链表和冷点链表的步骤。
10. 根据权利要求2或3所述的通用缓存的方法,其特征在于,还包括 为所述缓存段中各个数据设置包括正常状态、更新状态或删除状态的状态标识的步骤。
11. 根据权利要求10所述的通用缓存的方法,其特征在于,当所述缓存段中的数据的状态标识为更新状态时,还包括当所述数据被访问时,通过所述接口从外部数据源获取与所述数据对应的新数据,并更新所述缓存段的步骤;当所述缓存段中的数据的状态标识为删除状态时,还包括将通过所述接口从外部数据源获取的数据,覆盖所述处于删除状态的数据 并存储的步骤。
12. 根据权利要求1所述的通用缓存的方法,其特征在于,所述步骤二还包括步骤121,设置所述缓存段的最大存储空间参数和从外部数据源读取数据的接口的实现类参数;步骤122,在缓存系统启动时,初始化缓存中各个缓存段的名称和上述设置参数。
全文摘要
本发明提出了一种通用缓存的方法,用于获取缓存中存储的数据,其中,包括步骤一,在缓存中设置与外部数据源连接的用于获取外部数据的接口;步骤二,将缓存分配成多个缓存段,将一个数据只存放在一个缓存段里,设置每个缓存段的名称和数据的主健值;步骤三,当缓存系统收到数据访问请求时,根据请求访问的缓存段名称和数据的主健值,访问对应的缓存段,并判断缓存段中是否已存储所请求的数据,若已存储,则输出所请求的数据,若未存储,则通过接口从外部数据源获取所请求的数据,保存所请求的数据至缓存段中并输出。
文档编号G06F12/08GK101131673SQ20061011251
公开日2008年2月27日 申请日期2006年8月22日 优先权日2006年8月22日
发明者良 单, 吉 吕, 唐鲲鹏 申请人:中兴通讯股份有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1