什么是事务?
事务:被事务修饰的一系列的操作看成‘一个操作’,这些操作要么同时成功,要么同时失败。
-
eg:德玛西亚给拉克丝转500元钱:
1.德玛西亚的余额减500
2.拉克丝的余额加500
分析:
但如果在一、二部之间出错了,那么第一步就会成功而第二部不会成功,那这500元钱不就没了嘛,显然这样不现实,这种情况下用事务就很合适. -
在实现代码前,我们先学习几个sql语句:
1.开启一个事务-------START TRANSACTION;
2.回滚-----------------ROLLBACK;
解释:回到START TRANSACTION语句之前的状态。
3.提交(结束事务)--------COMMIT;
首先我们来看一下表原本的样子:
START TRANSACTION; -- 开启一个事务
UPDATE USES SET BALANCE = BALANCE - 500 WHERE USES.`NAME` = '德玛西亚';
啦啦啦
UPDATE USES SET BALANCE = BALANCE + 500 WHERE USES.`NAME` = '拉克丝';
执行上面三行代码后,再次查询表:
中间有不明中文,所以后面的sql语句没有执行。这个改变只是暂时的,它其实并没有变,当我们关闭这个窗口、或者我们再开启一个窗口查询,它的结果还是两人余额都是1000。我们看一个这个临时/暂时的数据,如果出错了,我们只要rollback即可”回滚“
回滚后(只执行rollback这一行代码):
如果发现临时的数据没有出错,那么执行commit即可,永久的将数据改变了。
COMMIT;
自动提交和手动提交
- 1.在mysql数据库中事务默认自动提交,而oracle数据库默认是手动提交的。
就是说:如果我们不手动的开启事务的话,一条DML语句(增删改,UPDATE)是自动提交的。 - 2.查看、修改自动提交
2.1 查看:
SELECT @@AUTOCOMMIT; -- 查询是否默认自动提交;
如果结果是1,那么就是默认自动提交;0则为手动提交。
2.2修改:
SET @@AUTOCOMMIT = 0; -- 修改为手动提交
事务的四大特征(这个很重要)
- 1.原子性:事务是不可分割的最小操作单元,要么同时成功,要么同时失败。
- 2.持久性:事务一旦回滚/提交后会持久的改变(无论是电脑关机等……都不会改变)
- 3.隔离性:多个事务之间,互相独立,减少影响。
- 4.一致性:事务执行前后,数据总量不变。eg:上面赚钱的例子,不管怎么赚钱,二者的钱数总量是不变的。
事务的隔离级别(了解即可)
多个事务同时操作一批数据,就会产生一些问题,而设置不同的隔离级别,就可以解决这些问题。(它很像Java中Thread安全的问题)
存在的问题:
- 1.脏读:一个事务读取到另一个事务还没有提交的数据。
- 2.虚读(不可重复读):在同一个事务里读取两次数据,这两次数据不一样。
- 3.幻读:一个事务操作(DML)表中所有事务,另一个事务增加了一条记录,那么前一个事务就会查询不到自己的修改
隔离级别:
- 1.READ UNCOMMITED;(读未提交)
存在的问题:脏读,虚读,幻读。 - 2.READ COMMITED;(读已提交)(oracle默认隔离级别)
存在的问题:虚读,幻读 - 3.REAPEATABLE READ;(可重复读)(mysql默认隔离级别)
存在的问题:幻读 - 4.SERIALIZABLE;(冲行化)
SERIALIZABLE可以解决以上所有问题。 - 但是注意,以上解决方法,从上到下虽然越来越安全,但是效率却越来越低。(要不然就全用最后一个得了呗)
- 查看隔离级别:SELECT @@TX_ISOLATION;
- 修改隔离级别:SET GLOBAL TRANSACTION ISOLATION LEVEL + 隔离等级;
隔离级别解释:
首先我们同时开两个cmd窗口,分别登录mysql。使用同一张表,两个都开启事务。
- 脏读:如果数据库隔离级别在READ UNCOMMITED,第一个cmd窗口修改某一列的数据,那么第二个窗口查询这个数据,查出来的就会是第一张表修改的数据(注意:第一张表的事务没有结束/提交!那如果第一张表的数据只是暂时的,一会就变了呢?)。对于这种情况(就叫脏读),我们只要把数据库的隔离级别改为READ COMMITED即可,也就是如果第一个事务没有提交,那么第二个cmd窗口就不会查询到(未提交的)修改的数据。
- 虚读:接着上一个的说下一个问题,现在不会再出现一个事务查询到另一个事务未提交的数据了。但是这个查询的食物可能两次查询的结果不一样。eg:另一个事务提交了,这个情况就叫虚读。同样我们只要再次设置隔离级别为REPEATABLE READ即可。尽管数据变了,也不会出现一个事务内查询到的结果是不同的了,只有这个查询的事务提交了,在次查询才会发生变化。
- (幻读的情况在mysql数据库中演示不出来,这里就不再演示了)
- SERIALIZABLE 这个就和Java线程安全问题中那个同步锁机制很像了。就是有一个锁,把这个表锁上了,在同一时间内,如果拿到了这个使用权力,不提交的话,别人永远也使用不了。别人就会一个处于堵塞状态,在等待。
- 一般我们不会去修改数据库的隔离等级,但可能有些特殊的需求,会根据不同的需求来用不同的隔离等级。