• 详细探究Redis事务与MySQL事务的区别【转】


    使用redis的小伙伴都知道,redis有事务的概念,同样的,mysql中也有事务的概念,那么这两者之间有什么关系呢?区别到底大不大?今天详细总结了一下,我们来一探究竟~

    在介绍区别之前,再次熟悉一下事务的概念:

    0. 概念

    事务:Transaction

    本质是一组命令的集合,可以一次执行多个命令,所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许插队。将一组需要一起执行的命令放到multiexec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。

    0.1 Redis事务的三个特性

    1. 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断;

    2. 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题;

    3. 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚;

    0.2 Redis事务执行的三个阶段

    1. 开启:以MULTI开始一个事务;

    2. 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面;

    3. 执行:由EXEC命令触发事务;

    举个例子:

    1、正常执行:

     2、放弃事务

     3、全体连坐(命令集合中含有错误的指令(注意是语法错误),均连坐,全部失败)

     4、冤有头,债有主(运行时错误,即非语法错误正确命令都会执行,错误命令返回错误

     但是我们注意到,在错误指令后面的指令也会被执行,这里就是"get age"得到的是“11”。

    好了,接下来我们看一下Mysql中的事务和redis中的事务的主要区别,

    主要从以下四个方面:

    1、事务命令

    mysql:

    • Begin:显式的开启一个事务;
    • Commit:提交事务,将对数据库进行的所有的修改变成永久性的;
    • Rollback:结束用户的事务,并撤销现在正在进行的未提交的修改;

    redis:

    • Multi:标记事务的开始;
    • Exec:执行事务的commands队列;
    • Discard:结束事务,并清除commands队列;

    2、默认状态

    mysql:

    • mysql会默认开启一个事务,且缺省设置是自动提交,即每成功执行一次sql,一个事务就会马上commit,所以不能rollback;
    • 默认情况下如上所述,但是非默认情况下,可以rollback

    redis:

    • redis默认不会开启事务,即command会立即执行,而不会排队,并不支持rollback

    3、使用方式

    mysql(包含两种方式):

    1. 用Begin、Rollback、commit显式开启并控制一个 新的 Transaction;
    2. 执行命令 set autocommit=0,用来禁止当前会话自动commit,控制 默认开启的事务;

    redis:

    1. 用multi、exec、discard,显式开启并控制一个Transaction。(注意:这里没有强调 “新的” ,因为默认是不会开启事务的)。

    4、实现原理

    mysql:

    • mysql实现事务,是基于undo/redo日志
    • undo记录修改前状态,rollback基于undo日志实现;
    • redo记录修改后的状态,commit基于redo日志实现;
    • 在mysql中无论是否开启事务,sql都会被立即执行并返回执行结果,只是事务开启执行后的状态只是记录在redo日志,执行commit之后,数据才会被写入磁盘;

    如: int insertSelective = serviceOrderMapper.insertSelective(s); 

    上述代码,insertSelective 将会被立即赋值(无论是否开启事务,只是结果或未被写入磁盘):

    redis:

    • redis实现事务,是基于commands队列;
    • 如果没有开启事务,command将会被立即执行并返回执行结果,并且直接写入磁盘
    • 如果事务开启,command不会被立即执行,而是排入队列,并返回排队状态(具体依赖于客户端(例如:spring-data-redis)自身实现)。调用exec才会执行commands队列;
    boolean a = redisTemplate.opsForZSet().add("generalService",orderId,System.currentTimeMillis());

    上述代码,

    • 如果没有开启事务,操作被立即执行,a将会被立即赋值(true/false);
    • 如果开启事务,操作不会被立即执行,将会返回null值,而a的类型是boolean,所以将会抛出异常:java.lang.NullPointerException;

    参考并致谢:

    1.Redis & Mysql 读写一致性问题

    2.Redis事务(Transaction)

    Over......

  • 相关阅读:
    Linux 下杀毒可用工具 clamav
    Docker 添加环境系统文件配置
    Docker 空间大小设置
    Docker 扩容 容器空间大小
    bzoj 1088 DP
    bzoj 1096 斜率优化DP
    spoj p104 Matrix-Tree定理
    bzoj 1016 深搜
    WC后记
    bzoj 1301 后缀数组
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14409390.html
Copyright © 2020-2023  润新知