您的位置:首页 > 数据库

NoSQL数据库的事务处理与数据一致性

2015-12-03 21:14 316 查看
        随着互联网的发展,NoSQL数据库开始流行起来。相比传统关系型数据库,NoSQL数据库可以说是为性能而生,但是在事务处理与一致性方面的能力明显不足,而这方面又是一个数据库产品不能不去面对的。好在主流NoSQL数据库产品还是在这方面有一些考虑的,本文以Memcache、Redis和Mongodb这三种当前最炙手可热的数据库为例,介绍一下它们各自是如何处理这一问题的。

1.Memcache

        Memcache在操作数据是执行以下步骤:取得数据(get命令)、修改i数据、保存数据(set命令)。这三步是单独进行,当多个不同的终端对同一个key值进行操作,即使时间再短,也存在发生不一致的可能。因此,Memcache提供了CAS(Check and Set)操作,来保证数据的一致性。CAS操作提供了两个命令,gets和cas来替代get和set命令。gets命令读取数据时会同时读取该key值得一个版本号(cas id)。cas id是数据的版本号,在更新数据时肯定会发生改变。cas命令进行更新时,要求提供版本号(cas
id),这时就就可以把刚才gets都出来版本号传给它。cas命令会比较这个版本号与数据库中key值得当前版本号,只有两者一致,保存才会成功。如果不一致,说明服务器上该数据已经被其它进程改变,保存就会失败。Memcache就是通过这个类似乐观锁的机制,保证数据的原子操作。

2.Redis

        Redis对事务的处理是比较简单的,它只能保证一个client发起的事务中的命令可以连续执行,不会被其它client的命令插入。当一个client发出multi命令时,就开启了事务,后续命令不会立即执行,而是放到一个队列中,直到执行了exec命令,Redis会顺序执行队列中的所有命令。discard命令可以退出事务,也就是清空队列中的所有命令,类似于事务回滚。但是实际上Redis并不是真正意义上的回滚,如果执行exec命令,当某操作发生错误,后续操作不再执行,但队列中已执行成功的命令不会回滚。这时Redis需要改进之处。Redis也有乐观锁机制,来保证数据一致性。它使用watch命令来监视给定的key,当执行exec时,如果监视的key从调用watch后发生了变化,则整个事务会失败。也可以调用watch多次监视多个key。注意,watch的key对整个连接有效,事务也一样。如果连接断开,监视和事务都会自动清除。执行exec、discard、unwatch命令都会清除连接中的所有监视。

3.Mongodb

         Mongodb的数据一致性,可以通过findAndModify命令来实现。这个命令可以将查询(find)和修改(modify)作为一个原子操作来进行,从而保证了数据的一致性。findAndModify命令既有“update”键也有“remove”键,但两者只能同时出现一个。mongodb 的很多命令都是保证是原子操作(atomic)像: $inc , $set等。

         MongoDB数据库中操作单个文档总是原子性的,然而,涉及多个文档的操作,通常被作为一个“事务”,而不是原子性的。相对于其它NoSQL数据库的简陋,Mongodb可谓功能强大,它被认为是最接近关系型数据库的NoSQL产品了。但是非常遗憾,它并不支持事务和锁机制。如果要实现“事务”,只能由客户端程序通过两阶段提交的方式来模拟了。例如可以通过以下步骤:

       


      第1步:先记录一条事务记录,将要修改的多行记录的修改值写到里面,并设置其状态为init(如果这时候操作中断,那么在重新启动时,会判断到它处于init状态,从而将其 保存的多行修改操作应用到具体的行上)。

      第2步:然后更新具体要修改的行,将刚才写的事务记录的标识写到它的tran字段中。

      第3步:将事务记录的状态从init变成pending(如果在这时候操作中断,那么在重新启动时,会判断到它的状态是pending,这时查看其所有对应的多条要修改的记录,如果 其tran值不为空,那么就进行第4步;如果值为空,说明第4步已经执行过了,直接将其状态从pending变成 commited就行)。

      第4步:将需要修改的多条记录的相应值加以修改,并且unset掉之前的tran字段。

      第5步:将事务记录那一条的状态从pending变成commited,事务至此完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: