Redis之坑:Redis与MySQL中事务的区别
Note:
- 该篇讨论的只是Redis与MySQL中事务的区别,并不能统一代表NO-SQL与关系型SQL;
- 在 MySQL 中只有使用了
Innodb
数据库引擎的数据库或表才支持事务;- 事务使用的目的 是统一管理 insert,update,delete, 这些
write操作
,以此来维护数据完整性。所以下文讨论的所有sql语句都是write操作
;
事务命令
MySQL:
- BEGIN:显式地开启一个事务;
- COMMIT:提交事务,将对数据库进行的所有修改变成为永久性的;
- ROLLBACK:结束用户的事务,并撤销正在进行的所有未提交的修改;
Redis:
- MULTI:标记事务的开始;
- EXEC:执行事务的commands队列;
- DISCARD:结束事务,并清除commands队列;
Redis之坑:理解Redis事务 中我们通过类比MySQL的BEGAIN
,COMMIT
,ROLLBACK
来理解Redis的事务命令。但是显然,它们有着本质区别。
默认状态
MySQL:
- MySQL会默认开启一个事务,且缺省设置是自动提交,即,每成功执行一个SQL,一个事务就会马上 COMMIT。所以不能Rollback。
Redis:
- Redis默认不会开启事务,即command会立即执行,而不会排队。并不支持Rollback(详情可见:Redis之坑:理解Redis事务 )
使用方式
MySQL:包含两种
- 用 BEGIN, ROLLBACK, COMMIT,显式开启并控制一个 新的 Transaction。
- 执行命令SET AUTOCOMMIT=0,用来禁止当前会话自动commit,控制默认开启的事务。
Redis:
- 用 MULTI, EXEC, DISCARD,显式开启并控制一个Transaction(注意:这里没有强调“新的”,因为默认是不会开启事务的)。
实现原理
很容易理解,Redis与MySQL中事务的区别其根本原因就是实现不同方式造成的。
MySQL:
- MySQL实现事务,是基于
UNDO/REDO日志
。UNDO日志
记录修改前
状态,ROLLBACK
基于UNDO日志实现;REDO日志
记录修改后
的状态 ,COMMIT
基于REDO日志实现;
- 在MySQL中无论是否开启事务,每一个SQL都会被立即执行并返回执行结果。但是事务开启后
执行后的状态
只是记录在REDO日志
,执行COMMIT
,数据才会被写入磁盘
。
int insertSelective = serviceOrderMapper.insertSelective(s);
所以,上述代码,insertSelective 将会被立即赋值(无论是否开启事务):
insertSelective = 受影响的行数;
Redis:
- Redis实现事务,是基于
COMMANDS队列
。 - 如果没有开启事务,command将会被立即执行并返回执行结果,并且直接写入磁盘;
- 如果事务开启,command不会被立即执行,而是排入队列并返回
排队状态
(具体依赖于客户端(例如:spring-data-redis)自身实现)。调用EXCE
才会执行COMMANDS队列
。
boolean a = redisTemplate.opsForZSet().add("generalService",orderId,System.currentTimeMillis());
上述代码,
- 如果没有开启事务,操作被立即执行,a 将会被立即赋值(true|false);
- 如果开启事务,操作未被立即之行,将会返回NULL值,而a的类型是boolean,所以将会抛出异常:
java.lang.NullPointerException - 原文地址http://www.bieryun.com/3334.html