具体实施方式
为使本申请的目的、技术方案和优点更加清楚,下面将结合本申请具体实施例及相应的附图对本申请技术方案进行清楚、完整地描述。显然,所描述的实施例仅是本申请一部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本申请保护的范围。
以下结合附图,详细说明本申请各实施例提供的技术方案。
随着计算机技术的发展,需要验证各数据库中的数据是否一致的场景已经越来越多,以区块链为例,区块链的本质是分布式数据库,区块链中每笔数据的变化,都会广播至全网的各区块链节点,每个节点都需要有全量的、一致的数据。在各节点中,数据往往会保存在多个数据单元中,一个数据单元可以是区块链中的一个区块,也可以是由多个区块共同构成的数据单元。在确定节点的状态值时,会以各个数据单元中数据的哈希值为叶子节点构建哈希树,例如默克尔树(Merkle Tree),然后将哈希树根节点的哈希值作为数据库的状态值,进而通过该状态值来唯一表征数据库的状态。
如图1所示为针对某一数据库构建的一种哈希树的数据结构示意图,在计算哈希树根节点的过程中,首先会计算各个数据单元中数据的哈希值,然后将得到的哈希值作为哈希树的叶子节点的值,再计算各叶子节点的父节点的哈希值,最终得到哈希树根节点的哈希值。当数据库中的数据变化后,需要重新确定数据库的状态值,这就需要重复上述计算哈希树根节点的过程,而如果数据库中的数据较多,便需要对大量的数据进行哈希运算,这会消耗较多的计算资源。
在一些类似的场景下,在确定数据库的状态值时,也会存在消耗较多的计算资源的问题,此处不再逐一赘述。为了解决该问题,本申请提供一种数据库状态确定方法,通过根据对目标数据库执行的状态迁移操作来确定目标数据库的状态。
下面将详细描述本申请提供的数据状态确定方法,该方法的执行主体可以是计算设备,例如分布式数据库中的数据库节点,或者区块链中的节点。此外,该方法的执行主体还可以是实现本申请提供的数据库状态确定方法的应用程序。为便于描述,下文以该方法的执行主体为计算设备为例,对该方法的实施方式进行介绍。可以理解,该方法的执行主体为计算设备只是一种示例性的说明,并不应理解为对该方法的限定。
本申请提供的数据库状态确定方法的实现流程示意图如图2所示,包括下述步骤:
步骤S101:确定对目标数据库执行的状态迁移操作;
其中,这里的状态迁移操作可以是导致数据库的状态发送改变的数据库操作,具体可以是数据写入操作、数据更新操作或者数据删除操作等操作,状态迁移操作中可以包含被处理的数据本身以及对数据的处理方式,比如数据写入操作会包含待写入的数据、以及数据要写入数据库中的具***置。这里的目标数据库可以是状态迁移操作所针对的数据库,该目标数据库可以是待确定状态值的任意数据库。
在实际应用中,具体确定状态迁移操作的方式可以有很多种,比如,在面向对象的应用程序中,状态迁移操作是由对象来实现的,那么可以通过确定状态迁移操作对应的数据操作对象来确定;或者,还可以是根据状态迁移操作对应的数据库操作语句来确定。这里的数据操作对象为面向对象的应用程序中用于执行数据库操作的数据的对象,面向对象的应用程序中,“对象”一般是指类在内存中装载的实例,具有相关的成员变量和成员函数。
由于数据库中数据的改变是通过状态迁移操作来实现的,那么在确定了状态迁移操作后,便可以确定执行该状态迁移操作后的数据库的状态。
步骤S102:根据执行所述状态迁移操作前所述目标数据库的状态值,以及确定的所述状态迁移操作,确定执行所述状态迁移操作后所述目标数据库的状态值。
这里的状态值用于表征目标数据库的状态,由于状态值可以用来对目标数据库进行一致性检验,因此,该状态值可以用于唯一地表征目标数据库中存储的数据的特征,该状态值比如可以是哈希值,也可以是全局唯一标识符。其中,哈希值是通过哈希函数对输入参数进行哈希计算得到的,全局唯一标识符可以是***分配的用于在***中唯一标识数据库状态的标识符
需要说明的是,本领域技术人员应当知晓,所谓唯一地表征并不应当理解为绝对意义上的唯一,而是在误差允许范围内的唯一,目前应用最广泛的哈希算法,在理论上也会存在输入的数据不同但输出的哈希值相同的情况,即所谓的哈希碰撞。
由于数据库中数据变化后的状态跟数据变化前的状态以及状态迁移操作有关,那么在确定针对目标数据库的状态迁移操作后,便可以根据执行该操作前目标数据库的状态值,以及确定的该状态迁移操作,确定执行该状态迁移操作后目标数据库的状态值。
在实际应用中,如步骤S101中所描述的,在面向对象的应用程序中,可以通过确定状态迁移操作对应的数据操作对象的方式来确定状态迁移操作,那么后续可以根据确定的该数据操作对象,以及执行该状态迁移操作前目标数据库的状态值,来确定执行该状态迁移操作后目标数据库的状态值。
为了方便通过简短的标识对不同的状态迁移操作进行区分,也可以通过某一特征值来唯一地表征状态迁移操作,状态迁移操作的特征值可以是哈希值,或者也可以是用于唯一标识状态迁移操作的全局唯一标识符等,此处不再赘述。为了方便对状态迁移操作的特征值和目标数据库的状态值进行计算,以得到执行状态迁移操作后的目标数据库的状态值,该特征值的数据格式可以与目标数据库状态值的数据格式相同或相近。
在实际应用中,对于面向对象的应用程序而言,可以确定数据操作对象的哈希值,然后根据确定的该数据操作对象的哈希值,以及执行状态迁移操作前目标数据库的状态值,确定执行状态迁移操作后目标数据库的状态值。
下面具体介绍本申请实施例中确定数据操作对象的哈希值的过程:
在确定数据操作对象的哈希值时,为了能够将数据操作对象的数据格式转换为哈希算法的输入所支持的格式,可以对数据操作对象执行序列化操作,序列化操作可以将对象的状态信息转换为可以存储或传输的格式。在对数据操作对象执行序列化操作后,便可以得到数据操作对象对应的序列化数据,该序列化数据的数据格式比如可以是二进制格式,二进制格式的数据可以作为哈希算法的输入。
在得到数据操作对象对应的序列化数据后,可以通过对该序列化数据进行哈希运算,得到该序列化数据的哈希值,即可将该序列化数据的哈希值作为该数据操作对象的哈希值。
需要说明的是,由于单次状态迁移操作往往会对应不止一个数据操作对象,比如区块链中节点每次状态迁移操作往往会对应多个数据操作对象,那么,在对状态迁移操作对应的数据操作对象进行序列化时,可以分别对各数据操作对象进行序列化,然后按顺序将得到的各序列化数据进行拼接,最终将得到的拼接后的序列化数据,作为状态迁移操作对应的序列化数据。
在按顺序将得到的各序列化数据进行拼接时,若各数据操作对象执行状态迁移操作的顺序是固定的,则按照执行状态迁移操作的顺序,对各数据操作对象对应的序列化数据进行拼接,得到拼接后的序列化数据;若各数据操作对象执行状态迁移操作的顺序是不固定的,则按照第一预定顺序,对各数据操作对象对应的序列化数据进行拼接,得到拼接后的序列化数据。然后可以通过哈希函数计算拼接后的序列化数据的哈希值,将该拼接后的序列化数据的哈希值,作为该状态迁移操作对应的数据操作对象的哈希值。
第一预定顺序可以是预先设定的拼接顺序,比如,如果各数据操作对象中数据的格式为key-value格式,那么可以按照key值从大到小的顺序,对各数据操作对象对应的序列化数据进行拼接。
在确定了状态迁移操作对应的数据操作对象的哈希值后,即可根据确定的数据操作对象的哈希值,以及执行该状态迁移操作前目标数据库的状态值,确定执行该状态迁移操作后目标数据库的状态值。具体来说,可以按照第二预定顺序,对数据操作对象的哈希值和执行该状态迁移操作前目标数据库的状态值进行拼接,得到拼接数据,确定该拼接数据的哈希值,将该拼接数据的哈希值作为执行该状态迁移操作后该目标数据库的状态值。
这里的第一预定顺序和第二预定顺序可以是预先设定的拼接顺序,在计算各数据库的状态值时,对数据进行拼接时应遵循相同的拼接顺序,否则即使各数据库之间的数据一致,也会导致计算出的状态值不同,进而无法准确检验各数据库的一致性。
需要说明的是,在某些情况下,两组不同的数据在拼接后可能会变成相同的拼接数据,比如对数据“hello”和“world”进行拼接可以得到拼接数据“helloworld”,而对数据“he”和“lloworld”进行拼接同样会得到“helloworld”,显然这两组数据在拼接前是不同的数据。那么,为了避免不同的数据在拼接后相同,在执行拼接操作时,可以使用分割字符来保证拼接后数据的唯一性,具体可以将预设分割字符放置于数据的拼接位置处,其中,预设分割字符可以由开发人员预先定义。例如,分割字符串为123,那么对于数据“hello”和“world”,在拼接后可以得到“hello123world”,对于数据“he”和“lloworld”,在拼接后可以得到“he123lloworld”。这样即可保证拼接后的两个数据是不同的数据。
基于上述使用分割字符对数据进行拼接的方式,在对各数据操作对象对应的序列化数据进行拼接时,可以将预设分割字符设置于进行拼接的至少两个序列化数据之间,再对设置预设分割字符后的各序列化数据进行拼接,得到拼接后的序列化数据。当然,在使用分割字符对数据进行拼接前,可以先判断不同组的数据在拼接后是否相同,当判断结果为拼接后相同时,再使用分割字符分别对各组数据进行拼接,得到拼接后的序列化数据。
通过本申请实施例提供的数据库状态确定方法,在确定数据发生变化后数据库的状态值时,通过确定对目标数据库执行的状态迁移操作,然后根据确定的状态迁移操作,以及执行该状态迁移操作前数据库的状态值,即可确定执行该状态迁移操作后数据库的状态值,相对于现有技术来说,无需对整个数据库中的所有数据进行运算,避免消耗过多的计算资源。同时,相对于现有的区块链技术中通过哈希树等树形结构来计算节点的哈希值而言,本申请实施例中无需构建树形结构,也就无需对树形结构中各节点的哈希值进行计算,避免消耗过多的计算资源。
在本申请实施例提供的一些优选方案中,会对数据操作对象进行序列化操作,以及对序列化数据进行哈希运算,这会消耗一定的计算资源,然而在分布式数据库中,尤其是在区块链中,数据库中存储的数据量往往是十分庞大的,对数据库中的数据进行哈希运算所消耗的计算资源,会远远大于本申请实施例的上述操作所耗费的计算资源。
按照上述数据库状态确定方法,便可确定数据库的状态值,后续便可以根据确定的状态值来对数据库进行一致性校验,下面将详细描述本申请提供的一种数据库一致性验证方法。
该方法的实现流程示意图如图3所示,包括下述步骤:
步骤S201:判断待校验的第一数据库和第二数据库的状态值是否相同;
这里的第一数据库和第二数据库为待进行校验的数据库,那么,可以根据本申请实施例提供的数据库状态确定方法分别确定第一数据库和第二数据库的状态值,具体确定过程请参照本申请中的相关描述,此处不再赘述。
步骤S202:若所述第一数据库和所述第二数据库的状态值相同,则确定所述第一数据库和所述第二数据库的状态一致。
若第一数据库和第二数据库的状态值不相同,则确定第一数据库和第二数据库的状态不一致。
基于本申请的上述发明构思,为了便于更好的理解本申请的技术特征、手段和效果,下面以目标数据库为区块链技术中的某一节点的数据库为例,对本申请的数据库状态确定方法做进一步说明。
本申请实施例中,以区块链应用为fabric区块链应用、目标数据库为LevelDB数据库以及数据库状态值为哈希值为例来进行描述,LevelDB数据库可以由数据操作对象来执行状态迁移操作,数据操作对象可以将key-value格式的数据写入LevelDB数据库中,区块链中在进行状态迁移操作时,会由共识算法来保证各节点间状态迁移的操作一致,且状态迁移发生的顺序一致。
对于每个区块链节点来说,在数据库中未写入任何数据时,各数据库的初始状态Sinit均为空,此时可以给定一个哈希值,这里将数据库初始状态的哈希值记为Hinit。
那么,在确定针对目标数据库的第i次状态迁移操作Transitioni发生时,便可以根据该操作重新计算目标数据库的哈希值,该过程的实现流程示意图如图4所示,包括下述步骤:
步骤S301:确定状态迁移操作对应的数据操作对象;
单次状态迁移操作往往会对应多个数据操作对象,针对节点的第i次状态迁移操作Transitioni可以表示为集合{op1,op2...,opN},其中,op为operation的简写,表示单个数据操作对象,意味着对于单个key-value对的一次写入操作,每个op的格式为Key:=NewVal,那么{op1,op2...,opN}即表示第i次状态迁移操作对N个key-value对进行写入操作。
步骤S302:将各数据操作对象序列化为二进制格式的序列化数据;
步骤S303:判断各数据操作对象执行状态迁移操作的顺序是否固定,若是,则执行步骤S304;若否,则执行步骤S305;
步骤S304:若各数据操作对象的执行顺序固定,则按照执行状态迁移操作的顺序,对各数据操作对象对应的序列化数据进行拼接,得到拼接后的序列化数据,进入步骤S306;
步骤S305:若各数据操作对象的执行顺序不固定,则按照第一预定顺序,对各数据操作对象对应的序列化数据进行拼接,得到拼接后的序列化数据;
这里的第一预设顺序可以为按照key值从大到小的顺序。
步骤S306:确定拼接后的序列化数据的哈希值,作为该状态迁移操作对应的哈希值;
将拼接后的序列化数据作为哈希算法的输入,进行哈希计算,得到拼接后的序列化数据的哈希值,即为状态迁移操作Transitioni的哈希值Hash(Transitioni)。
步骤S307:按照第二预定顺序,对该状态迁移操作对应的哈希值和执行该状态迁移操作前目标数据库的哈希值Hi-1进行拼接,得到拼接数据;
步骤S308:确定该拼接数据的哈希值,将该拼接数据的哈希值作为执行状态迁移操作Transitioni后目标数据库的哈希值Hi。
最终得到的执行状态迁移操作Transitioni后目标数据库的哈希值Hi可用如下公式表示:
Hi:=Hash(Hi-1||Hash(Transitioni))
其中,H0=Hinit,||表示拼接操作,Hash(x)为哈希函数,表示对输入的数据x执行哈希运算,哈希函数比如可以是SHA3。
通过本申请实施例提供的数据库状态确定方法,在确定数据发生变化后数据库的哈希值时,通过确定对目标数据库执行的状态迁移操作Transitioni,然后确定与该状态迁移操作对应的哈希值Hash(Transitioni),根据执行该状态迁移操作前数据库的哈希值Hi -1,即可确定执行该状态迁移操作后数据库的状态值Hi。相对于现有技术来说,无需对整个节点的数据库中的所有数据进行运算来计算哈希值,避免消耗过多的计算资源。同时,相对于现有的区块链技术中通过哈希树等树形结构来计算节点的哈希值而言,本申请实施例中无需构建树形结构,也就无需对树形结构中各节点的哈希值进行计算,进一步减少了对计算资源的消耗。
以上为本申请实施例提供的数据库状态确定方法,基于同样的思路,本申请实施例还提供相应的数据库状态确定装置,如图5所示,该装置具体包括:
第一确定单元401,确定对目标数据库执行的状态迁移操作;
第二确定单元402,根据执行所述状态迁移操作前所述目标数据库的状态值,以及确定的所述状态迁移操作,确定执行所述状态迁移操作后所述目标数据库的状态值,所述状态值用于表征所述目标数据库的状态。
本申请实施例中,数据状态确定的具体实施方式还有很多,在一种实施方式中,第一确定单元401,确定用于对目标数据库执行所述状态迁移操作的数据操作对象;
第二确定单元402,根据执行所述状态迁移操作前所述目标数据库的状态值,以及确定的所述数据操作对象,确定执行所述状态迁移操作后所述目标数据库的状态值。
在一种实施方式中,第二确定单元402具体包括第一哈希值确定子单元403和第一状态值确定子单元404,其中:
所述第一哈希值确定子单元403,确定所述数据操作对象的哈希值;
所述第一状态值确定子单元404,根据确定的所述数据操作对象的哈希值,以及执行所述状态迁移操作前所述目标数据库的状态值,确定执行所述状态迁移操作后所述目标数据库的状态值。
在一种实施方式中,所述第一哈希值确定子单元403,具体包括序列化数据确定子单元405和第二哈希值确定子单元406,其中:
所述序列化数据确定子单元405,对所述数据操作对象进行序列化,得到序列化数据;
所述第二哈希值确定子单元406,确定所述序列化数据的哈希值,将所述序列化数据的哈希值作为所述数据操作对象的哈希值。
在一种实施方式中,所述序列化数据确定子单元405,具体包括第一拼接子单元407和第二拼接子单元408:
在一种实施方式中,所述第一拼接子单元407,在存在不止一个用于对目标数据库执行所述状态迁移操作的数据操作对象,且各所述数据操作对象执行状态迁移操作的顺序确定时,按照执行状态迁移操作的顺序,对各所述数据操作对象对应的序列化数据进行拼接,得到拼接后的序列化数据;
所述第二拼接子单元408,在存在不止一个用于对目标数据库执行所述状态迁移操作的数据操作对象,且各所述数据操作对象执行状态迁移操作的顺序不确定时,按照第一预定顺序,对各所述数据操作对象对应的序列化数据进行拼接,得到拼接后的序列化数据。
为了防止不同组数据在拼接后相同,在一种实施方式中,所述第二拼接子单元408,将预设分割字符设置于至少两个序列化数据之间,对设置预设分割字符后的各序列化数据进行拼接,得到拼接后的序列化数据。
在一种实施方式中,所述第一状态值确定子单元404,按照第二预定顺序,对所述数据操作对象的哈希值和执行所述状态迁移操作前所述目标数据库的状态值进行拼接,得到拼接数据;
确定所述拼接数据的哈希值,将所述拼接数据的哈希值作为执行所述状态迁移操作后所述目标数据库的状态值。
在一种实施方式中,所述目标数据库为区块链中任一节点对应的数据库。
在一种实施方式中,所述状态值用于唯一地表征所述目标数据库中存储的数据的特征。
本申请实施例提供的数据库状态确定装置,在确定数据发生变化后数据库的状态值时,通过确定对目标数据库执行的状态迁移操作,该状态迁移操作为导致数据发生该变化的状态迁移操作,然后根据确定的状态迁移操作,以及执行该状态迁移操作前数据库的状态值,确定执行该状态迁移操作后数据库的状态值,相对于现有技术来说,无需对整个数据库中的所有数据进行运算,避免消耗过多的计算资源。
本申请实施例还提供相应的数据库一致性验证装置,如图6所示,该装置具体包括:
判断单元501,判断待校验的第一数据库和第二数据库的状态值是否相同,所述第一数据库和所述第二数据库的状态值是通过权利要求10-16任一权项所述装置确定的;
一致性确定单元502,在确定所述第一数据库和所述第二数据库的状态值相同时,则确定所述第一数据库和所述第二数据库的状态一致。
需要说明的是,在20世纪90年代,对于一个技术的改进可以很明显地区分是硬件上的改进(例如,对二极管、晶体管、开关等电路结构的改进)还是软件上的改进(对于方法流程的改进)。然而,随着技术的发展,当今的很多方法流程的改进已经可以视为硬件电路结构的直接改进。设计人员几乎都通过将改进的方法流程编程到硬件电路中来得到相应的硬件电路结构。因此,不能说一个方法流程的改进就不能用硬件实体模块来实现。例如,可编程逻辑器件(Programmable Logic Device,PLD)(例如现场可编程门阵列(FieldProgrammable Gate Array,FPGA))就是这样一种集成电路,其逻辑功能由用户对器件编程来确定。由设计人员自行编程来把一个数字***“集成”在一片PLD上,而不需要请芯片制造厂商来设计和制作专用的集成电路芯片。而且,如今,取代手工地制作集成电路芯片,这种编程也多半改用“逻辑编译器(logic compiler)”软件来实现,它与程序开发撰写时所用的软件编译器相类似,而要编译之前的原始代码也得用特定的编程语言来撰写,此称之为硬件描述语言(Hardware Description Language,HDL),而HDL也并非仅有一种,而是有许多种,如ABEL(Advanced Boolean Expression Language)、AHDL(Altera HardwareDescription Language)、Confluence、CUPL(Cornell University ProgrammingLanguage)、HDCal、JHDL(Java Hardware Description Language)、Lava、Lola、MyHDL、PALASM、RHDL(Ruby Hardware Description Language)等,目前最普遍使用的是VHDL(Very-High-Speed Integrated Circuit Hardware Description Language)与Verilog。本领域技术人员也应该清楚,只需要将方法流程用上述几种硬件描述语言稍作逻辑编程并编程到集成电路中,就可以很容易得到实现该逻辑方法流程的硬件电路。
控制器可以按任何适当的方式实现,例如,控制器可以采取例如微处理器或处理器以及存储可由该(微)处理器执行的计算机可读程序代码(例如软件或固件)的计算机可读介质、逻辑门、开关、专用集成电路(Application Specific Integrated Circuit,ASIC)、可编程逻辑控制器和嵌入微控制器的形式,控制器的例子包括但不限于以下微控制器:ARC 625D、Atmel AT91SAM、Microchip PIC18F26K20以及Silicone Labs C8051F320,存储器控制器还可以被实现为存储器的控制逻辑的一部分。本领域技术人员也知道,除了以纯计算机可读程序代码方式实现控制器以外,完全可以通过将方法步骤进行逻辑编程来使得控制器以逻辑门、开关、专用集成电路、可编程逻辑控制器和嵌入微控制器等的形式来实现相同功能。因此这种控制器可以被认为是一种硬件部件,而对其内包括的用于实现各种功能的装置也可以视为硬件部件内的结构。或者甚至,可以将用于实现各种功能的装置视为既可以是实现方法的软件模块又可以是硬件部件内的结构。
上述实施例阐明的***、装置、模块或单元,具体可以由计算机芯片或实体实现,或者由具有某种功能的产品来实现。一种典型的实现设备为计算机。具体的,计算机例如可以为个人计算机、膝上型计算机、蜂窝电话、相机电话、智能电话、个人数字助理、媒体播放器、导航设备、电子邮件设备、游戏控制台、平板计算机、可穿戴设备或者这些设备中的任何设备的组合。
为了描述的方便,描述以上装置时以功能分为各种单元分别描述。当然,在实施本申请时可以把各单元的功能在同一个或多个软件和/或硬件中实现。
本领域内的技术人员应明白,本发明的实施例可提供为方法、***或计算机程序产品。因此,本发明可采用完全硬件实施例、完全软件实施例、或结合软件和硬件方面的实施例的形式。而且,本发明可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、CD-ROM、光学存储器等)上实施的计算机程序产品的形式。
本发明是参照根据本发明实施例的方法、设备(***)、和计算机程序产品的流程图和/或方框图来描述的。应理解可由计算机程序指令实现流程图和/或方框图中的每一流程和/或方框、以及流程图和/或方框图中的流程和/或方框的结合。可提供这些计算机程序指令到通用计算机、专用计算机、嵌入式处理机或其他可编程数据处理设备的处理器以产生一个机器,使得通过计算机或其他可编程数据处理设备的处理器执行的指令产生用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的装置。
这些计算机程序指令也可存储在能引导计算机或其他可编程数据处理设备以特定方式工作的计算机可读存储器中,使得存储在该计算机可读存储器中的指令产生包括指令装置的制造品,该指令装置实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能。
这些计算机程序指令也可装载到计算机或其他可编程数据处理设备上,使得在计算机或其他可编程设备上执行一系列操作步骤以产生计算机实现的处理,从而在计算机或其他可编程设备上执行的指令提供用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的步骤。
在一个典型的配置中,计算设备包括一个或多个处理器(CPU)、输入/输出接口、网络接口和内存。
内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(RAM)和/或非易失性内存等形式,如只读存储器(ROM)或闪存(flash RAM)。内存是计算机可读介质的示例。
计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(PRAM)、静态随机存取存储器(SRAM)、动态随机存取存储器(DRAM)、其他类型的随机存取存储器(RAM)、只读存储器(ROM)、电可擦除可编程只读存储器(EEPROM)、快闪记忆体或其他内存技术、只读光盘只读存储器(CD-ROM)、数字多功能光盘(DVD)或其他光学存储、磁盒式磁带,磁带磁磁盘存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括暂存电脑可读媒体(transitory media),如调制的数据信号和载波。
还需要说明的是,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、商品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、商品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个……”限定的要素,并不排除在包括所述要素的过程、方法、商品或者设备中还存在另外的相同要素。
本申请可以在由计算机执行的计算机可执行指令的一般上下文中描述,例如程序模块。一般地,程序模块包括执行特定任务或实现特定抽象数据类型的例程、程序、对象、组件、数据结构等等。也可以在分布式计算环境中实践本申请,在这些分布式计算环境中,由通过通信网络而被连接的远程处理设备来执行任务。在分布式计算环境中,程序模块可以位于包括存储设备在内的本地和远程计算机存储介质中。
本说明书中的各个实施例均采用递进的方式描述,各个实施例之间相同相似的部分互相参见即可,每个实施例重点说明的都是与其他实施例的不同之处。尤其,对于***实施例而言,由于其基本相似于方法实施例,所以描述的比较简单,相关之处参见方法实施例的部分说明即可。
以上所述仅为本申请的实施例而已,并不用于限制本申请。对于本领域技术人员来说,本申请可以有各种更改和变化。凡在本申请的精神和原理之内所作的任何修改、等同替换、改进等,均应包含在本申请的权利要求范围之内。