redis 是一个高性能的key-value 数据库。作为no sql 数据库redis 与传统关系型数据库相比有简单灵活、数据结构丰富、高速读写等优点。

本文主要针对redis 在事物方面的处理与传统关系型数据库(使用mysql)进行比对,所使用的环境为ubuntu 14.04.1,mysql 5.5.49,redis 3.2.3。

1操作事务命令

mysql 使用start transaction 开启事物,rollback 回滚事物,commit 提交事物。redis 使用multi 开始事物,discard 取消事物,exec 提交事物。开始实验前为mysql 和redis 准备测试数据,tom1 账户准备1000元,tom2 账户准备500元。

(图1-数据准备)

场景1:使用事务从tom1转100元到tom2 。

步骤如下:

 

mysql

redis

开启事物

start transaction

multi

tom1 - 100

update tom1

decrty tom1 100

queued

查询tom1 余额

tom1余额减少了100

get tom1

queued

tom2 + 100

update tom2

incrby tom2 100

queued

查询tom2 余额

tom2余额增加了100

get tom2

queued

提交事物

commit

exec

执行queue中的语句。

1) (integer) 900

2) "900"

3) (integer) 600

4) "600"

查询tom1,tom2余额

select * from account where name in (‘tom1’,’tom2’);

tom1金额减少100,tom2账户增加了100

mget tom1 tom2

tom1金额减少100,tom2账户增加了100

(图2-mysql 事务执行过程)

(图3-redis 事务执行过程)

从场景1中可以看出mysql 开启事务后事务中的sql 语句在commit 之前就已经执行了sql 语句的,只是并未真正提交到数据库。redis 使用multi 开启事务后,编写的sql 语句都进入queue 队列中,待执行exec 提交事物时才一次性按进入queue 队列的顺序提交到数据库。同样针对回滚,mysql 执行rollback 会将提交的数据回滚,redis 因为没有提交到数据,使用discard 只是单纯取消在queue 中的sql 语句。

场景2: 在执行tom1 向tom2 转过程中100元的过程中使用了语法错误的sql。

步骤如下:

 

mysql

redis

开启事物

start transaction

multi

tom1 - 100

update tom1

decrty tom1 100

queued

查询tom1 余额

tom1余额减少了100

get tom1

queued

tom2 + 100

使用错误命令为tom2+100

使用错误命令为tom2+100

查询tom2 余额

tom2余额未变

get tom2

queued

提交事物

commit

exec

因为queue中存在语法错误的语句,直接discard事务中的语句

查询tom1,tom2余额

select * from account where name in (‘tom1’,’tom2’);

tom1金额减少100,tom2账户金额未变

mget tom1 tom2

tom1,tom2金额未变

(图4-mysql 事务中存在语法错误语句)

(图5-redis 事务中存在语法错误语句)

从场景2中可以看出,mysql 事务即使遇到错误的语句也会提交正确的sql 到数据库,需要程序员控制当遇到语句异常时进行回滚,redis 与mysql 不同,提交事务时当queue 中有语法错误语句会discard 整个事务中的sql 语句。

场景3: 在执行tom1 向tom2 转过程中100元的过程中使用了错误的执行对象。

步骤如下:

 

mysql

redis

开启事物

start transaction

multi

tom1 - 100

update tom1

decrty tom1 100

queued

查询tom1 余额

tom1余额减少了100

get tom1

queued

tom2 + 100

使用错误对象命令为tom2+’hundrud’

使用错误命令为tom2+’hundred’

查询tom2 余额

tom2余额未变

get tom2

queued

提交事物

commit

exec

逐条执行

查询tom1,tom2余额

select * from account where name in (‘tom1’,’tom2’);

tom1金额减少100,tom2账户金额未变

mget tom1 tom2

tom1金额减少100,tom2账户金额未变

(图6-mysql 中存在操作错误对象的sql 语句)

(图7-redis 中存在操作错误对象的sql语句)

从场景3中可以看出,mysql 和redis 事务当遇到操作对象类型不正确的时候都会提交执行事务。

2事务锁

在关系型数据库中主要通过乐观锁和悲观锁进行数据库事务的并发控制。而在redis 中是通过watch 加乐观锁对数据库进行并发控制。

mysql 悲观锁是通过select * from table where <condition> for update将数据加锁,导致其他线程或事务不能更新该数据。相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。数据版本为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。

关系型数据库mysql 实现数据版本主要有两种方式,第一种是使用版本号,第二种是使用时间戳。使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。

(图8-mysql乐观锁)

图8展示了mysql 乐观锁的示例,开启两个mysql 客户端,客户端1执行start transaction 查询数据,这时客户端2更新了客户端1查询到的数据及version 字段,然后客户端1在第3步试图更新在第一步中查询到的数据时因version 已改变因此更新失败。

(图9-redis 乐观锁(watch))

redis 是通过watch 命令监控数据是否发生变化实现乐观锁的。如图9所示打开两个redis 客户端,客户端1对数据tom2 进行watch,打开事务更改tom1,tom2,客户端2更改客户端1中watch 的对象,步骤3客户端1提交事务由于watch 的对象被更改了,导致事务放弃执行。

3事务的ACID 性质

下面讨论下事务的ACID 性质。传统关系型数据库事务具备ACID 性质,这里不做详细讨论。

针对Redis 事务具有原子性(Atomicity),一致性(Consistency),和隔离性(Isolation),当redis 在持久化模式运行时,也具备持久性(Durability)。在场景1~3和乐观锁示例中redis 全部执行事务队列中的sql 语句即使其中sql存在操作对象错误,要么全部discard放弃执行,因此redis 事务具有原子性(Atomicity)。

redis 事务在执行过程中发生错误或进程被终结,都能保证数据的一致性(Consistency)。因为redis 使用单线程串行方式来执行事务的,在执行事务期间不会对事务进行中断(一致性),因此redis 事务也具有隔离性(Isolation)。redis 可以只将运行结果保存在内存中,但当redis 服务器使用AOF 持久化模式并appendfsync 设置为always 时,程序执行sql 后会调用sync 函数将数据保存到硬盘里,因此redis 事务也可以具有持久性(Durability)。

通过下表对redis 事务和关系型数据库事务做一个简单的总结。

 

关系型数据库(mysql)

redis

开启事务

start transaction命令

multi命令

回滚事务

使用rollback命令可以回滚事务

不能回滚事务。但使用discard命令可以放弃事务queue中的sql

提交事务

commit命令

即使遇到sql语法错误也会提交事务

exec命令

如果遇到sql语法错误会放弃事务中的sql

悲观锁

使用select ... for update实现悲观锁

乐观锁

通常使用version或时间戳来实现乐观锁

使用watch监控对象变化来实现乐观锁

原子性(Atomicity)

具备

具备

一致性(Consistency)

具备

具备

隔离性(Isolation)

具备

具备

持久性(Durability)

具备

当redis服务器使用AOF持久化模式并appendfsync设置为always时具备

转自:http://www.sohu.com/a/111695683_464008

redis事务与关系型数据库事务比较的更多相关文章

  1. Cassandra事务与关系型数据库事务有何区别

    Cassandra不会使用回滚和锁机制来实现关系型数据的ACID事务,相比较于提供原子性,隔离性和持久化,Cassandra提供最终(可调节的)一致性,让用户决定为每个事务提供强一致性或者最终一致性. ...

  2. Java Redis系列1 关系型数据库与非关系型数据库的优缺点及概念

    Java Redis系列1 关系型数据库与非关系型数据库的优缺点及概念 在学习redis之前我们先来学习两个概念,即什么是关系型数据库什么是非关系型数据库,二者的区别是什么,二者的关系又是什么? ** ...

  3. 数据库事务隔离级ORACLE数据库事务隔离级别介绍

    本文系转载,原文地址:http://singo107.iteye.com/blog/1175084 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted.Read committ ...

  4. Spring的事务管理和数据库事务相关知识

    1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱.         比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱. ...

  5. Spring事务传播及数据库事务操作

    从Spring 事务配置说起 先看看Spring 事务的基础配置 <aop:aspectj-autoproxy proxy-target-class="true"/> ...

  6. Redis 01: 非关系型数据库 + 配置Redis

    数据库应用的发展历程 单机数据库时代:一个应用,一个数据库实例 缓存时代:对某些表中的数据访问频繁,则对这些数据设置缓存(此时数据库中总的数据量不是很大) 水平切分时代:将数据库中的表存放到不同数据库 ...

  7. 关系型数据库事务遵循ACID原则

    事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性: 1.A (Atomicity) 原子性 原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功 ...

  8. Redis(1.3)Redis的基本特性(事务、多数据库)

    [1]两大特性 (1)多数据库 1个redis实例 可以有16个数据库,默认下标为0~15,默认连接到的是 0 下标的数据库. (2)事务 [2]多数据库 [2.1]概念 1个redis实例 可以有1 ...

  9. Redis 如何与数据库事务保持一致

    考虑一个问题,redis 如何 与 数据库保持一致性的问题. 举栗子:如果我们在开发过程中遇到这样的一种情况,我们删除 redis中token 的同时 也需要修改数据库中 储存的 token 的状态为 ...

随机推荐

  1. table 表格 细边框 最简单样式

    table 表格细边框的效果实现方法虽然不难,但网上简单有效的方法却很少,在此记录一下 css 样式 /** table 细边框 **/ table{border-collapse: collapse ...

  2. webgl核心要素

    WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,提供硬件3D加速渲染, ...

  3. Css3动画效果,彩色文字效果,超简单的loveHeart

    <!DOCTYPE html><html><head><meta charset="utf-8" /><title>Cs ...

  4. 算法与数据结构基础 - 回溯(Backtracking)

    回溯基础 先看一个使用回溯方法求集合子集的例子(78. Subsets),以下代码基本说明了回溯使用的基本框架: //78. Subsets class Solution { private: voi ...

  5. vue 辅助开发工具(利用node自动生成相关文件,自动注册路由)

    vue 辅助开发工具 前言 有没有因为新建view,component,store的繁琐操作而苦恼,需要新建文件件,新建vue文件,新建js文件,注册路由...等一系列无价值操作浪费时间,为了解决这个 ...

  6. Java一个简单的文件工具集

    class FileUtils { //文件目录下文件总数目 public static int fileNumber(File dir) { int filenumber = 0; if(dir.e ...

  7. K8S搭建-1 Master 2 Workers(dashboard+ingress)

    本文讲述k8s最新版的搭建(v1.15.2) 分如下几个topic步骤: 各个节点的基本配置 master节点的构建 worker节点的构建 安装dashboard 安装ingress 常见命令 do ...

  8. Linux 使用命令 1

    fold : Usage: fold [OPTION]... [FILE]...Wrap input lines in each FILE (standard input by default), w ...

  9. DotNetCore 3.0 助力 WPF本地化

    概览 随着我们的应用程序越来越受欢迎,我们的下一步将要开发多语言功能.方便越来越多的国家使用我们中国的应用程序, 基于 WPF 本地化,我们很多时候使用的是系统资源文件,可是动态切换本地化,就比较麻烦 ...

  10. java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?

    这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...