事务命令
mysql:
- Begin:显式的开启一个事务
- Commit:提交事务,将对数据库进行的所有的修改变成永久性的
- Rollback:结束用户的事务,并撤销现在正在进行的未提交的修改
redis:
- Multi:标记事务的开始
- Exec:执行事务的commands队列
- Discard:结束事务,并清除commands队列
默认状态
mysql:
- mysql会默认开启一个事务,且缺省设置是自动提交,即每成功执行一次sql,一个事务就会马上commit,所以不能rollback
redis:
- redis默认不会开启事务,即command会立即执行,而不会排队,并不支持rollback
使用方式
mysql(包含两种方式):
- 用Begin、Rollback、commit显式开启并控制一个 新的 Transaction
- 执行命令 set autocommit=0,用来禁止当前会话自动commit,控制 默认开启的事务
redis:
- 用multi、exec、discard,显式开启并控制一个Transaction。(注意:这里没有强调 “新的” ,因为默认是不会开启事务的)。
实现原理
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)自身实现)。调用exec
才会执行commands队列
boolean a = redisTemplate.opsForZSet().add("generalService",orderId,System.currentTimeMillis());
上述代码,
- 如果没有开启事务,操作被立即执行,a将会被立即赋值(true/false)
- 如果开启事务,操作不会被立即执行,将会返回null值,而a的类型是boolean,所以将会抛出异常:java.lang.NullPointerException