前言
目前为止我们已经学习了有一定数量的sql命令和sql语言的概念了。
那么在实际使用过程中,这些语句是一句一句按顺序执行的吗?sql语言也有主流编程语言一样的“顺序结构、循环结构、分支结构”这么一说吗?
其实在实际的业务当中,sql语言可能不会像编程语言那样有三类明显的语句结构。
但是sql中语句语句之间的关系必然也是有的,想象一下银行的转账操作,一个账户扣款和另一个账户的进账必须看作一个整体,少哪个步骤都会造成严重的后果。
这就是sql语言的事务——
事务的概念
多条语句作为一个整体进行操作的功能,称为数据库事务。一个事务可以确保在这事务范围内的所有操作只能全部成功或者全部失败,如果事务中任何语句执行失败,则之前执行的命令也全部撤销,效果等同于没有执行这整个事务的所有语句。
我们来看看上面提到的汇款过程:
update acc set money=money-100 where id=001; update acc set money=money+100 where id=002; 复制代码
我们用update命令改变数据库指定记录的数据,第一条(前两行)扣款,第二条(后两行)入账。如果按照传统的命令一条条执行的话,一旦在扣款完成后,入账过程出错(比如查找不到id为002的记录),那这100块就永远从流通中消失了(实际存在银行里的财富没有少,100块可能被当作银行吞钱),错误一多,就带来了严重的责任事故。
而用事务就不一样了,哪怕第二条语句出错,第一条语句也会撤销,相当于转账失败,至少双方没有财富损失
数据库事务的特性
普遍认为,数据库的事务具有以下4个特性。用商科常见的首字母简拼法,就是ACID:
- Atomic,原子性。事务中的所有sql语句作为原子单元执行,要么全部成功,要么全部不执行。
- Consistent,一致性,事务完成后,所有状态一致(也可以理解成数据库完整性约束没有被破坏)。这个“状态一致”比较抽象,其实这个概念和具体应用场景有关,比如上面提到的汇款,汇款后,001加了100块,002收入100块,和汇款前总额是不变的。
- Isolation,隔离性,多个事务并发执行时,每个事务作出的修改必须与其他事务隔离。详细来说就是,不同事务在中间过程对同一个数据进行操作时,每个事务有各自完整的数据空间,他们的修改都是彼此隔离的,不会相互影响。
- Duration,持久性,事务完成后,对数据库的修改会被持久化储存。即事务完成后不会再出现回滚情况,即便系统故障也能在重启后恢复事务成功后的状态。(懂电脑的人都知道内存和硬盘的区别吧?这里可以类比一下)
隐式事务和显式事务
其实仔细一想,一条完整的sql语句好像就是一个事务。他满足事务的所有特性。
的确,对于单条事务,数据库系统会自动将其作为事务执行。一条语句的事务被称为“隐式事务”
而我们前面提到的多条语句组成的事务该如何设置呢?我们可以使用begin&commit
包裹着代码块进行声明:
begin; update acc set money=money-100 where id=001; update acc set money=money+100 where id=002; commit; 复制代码
如上,我们这样就完成了一个代码块的事务声明(也可以说是一个事务的提交,毕竟是commit,看你怎么理解了)。当然,这样包含多条语句的事务叫做 “显式事务”
顾名思义,commit后,这个事务的结果就被永久保存了,除非我们有别的命令去修改,不然他不会回滚到以前的状态了。如果我们希望某个事务失败并回滚,可以使用rollback
命令替换commit
:
begin; update acc set money=money-100 where id=001; update acc set money=money+100 where id=002; rollback; 复制代码
这样整个事务就失败,并回到之前的状态了。