事务
TCL(Transaction Control Language 事务控制语言)
事务概念::一个或一组SQL语句组成的一个执行单元,这个单元要么全执行,要么全不执行。是相互依赖的,其中某行语句发生失败或者错误,整个单元将会回滚(所有收到影响的数据将会回到事务开始以前的状态)。
举例:转账
A有1000元,B有1000元,现在A要给B 500元
伪代码:
set money=1500 where name='B'
set money =500 where name ='A';
(我们都知道转账是比较严谨的事情,不可以中途出现意外,A已经把钱转出去了,但是B收不到这种情况是不能
出现的,所以这两行语句要么都要执行成功,要么都执行失败回到最初的样子,只有这样他们的钱的总数不会变
(A,B钱之和不变),所以把他们弄成一个事务,保证不会有失误。)
事务的ACID属性:(面试重点)
(1)原子性(Atomicity):是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
(2) 一致性(Consistency):事务必须使数据库从一个一致性状态转换到另一个一致性的状态。(比如转账之前,A和B的钱总和为2000元,转完账之后两个人的钱总和还是为2000,这是不变的。)
(3)隔离性(Isolation):指一个事务的执行不能被其他事务干扰,并发执行的各个事务之间不能相互干扰。(下面有详细介绍)
(并发–> 多个事务在一个CPU上间隔执行,并行–>多个事务在多个CPU上同时执行)
实际操作中很有可能多个事务并发的去处理同一个数据库数据,所以很难做
到不相互影响,很难做到隔离性,一般都达不到隔离性。
(4)持久性(Durability):指一个事务一旦被提交,它对数据库中数据的改变是永久性的,比如删除,无法撤回的。
事务的创建:
隐式事务:
事务没有明显的开启结束标记。
比如:insert,update,delete等语句。(一行一个事务)
显示事务:
事务具有明显的开启和结束(提交commit或回滚rollback)
比如 :多行语句一起执行,转账案例
开启就是把自动提交功能禁用,最后把多行语句一次性提交或回滚
禁止自动提交功能 set autocommit=0;(不然写一句就会执行一句)
数据库的隔离级别:
一个事务与其他事务隔离的程度称为隔离级别。级别越高数据一致性越好,但并发性越弱。
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种数据并发的问题。
(1)脏读:对于两个事务A,B,若A读取了已经被B更新但还没被提交的字段,之后,B提交,那么A读取的内容就是临时且无效的。
(2)不可重复读:对于两个事务A,B,A读取了一个字段之后B更新了该字段,之后A再次读取同一个字段,值就不一样了,两次读取的结果不同了。
(3)幻读: 对两个事务A,B,A从一个表中读取了字段,然后B在该表中插入了一些新的行,如果A再次读取同一个表,就会出现新的行。
(脏读和幻读主要区别在于,脏读是更新了数据没被提交就被别的事务读取了,幻读是插入了新的行)
可以通过设置隔离级别来避免这种问题
oracle 默认 read committed(不可重复读)
MySQL 默认 repeatable read(可重复读)
每启动一个MySQL程序,就会获得一个单独的数据库连接,每个数据库连接都会有一个全局变量 @@tx_isolation ,表示当前的隔离级别。
查看当前的隔离级别:select @@tx-isolation;
设置当前MySQL连接的隔离级别:
set transaction isolation level read commited;
设置数据库系统的全局的隔离级别:
set global transaction isolation level read commited;
举例伪代码:
set autocommit=0; //0代表自动提交关闭,开启事务(不会一行提交一次)
update.............;//操作代码
commit; 或者 rollback;
(回滚的时候需要设置保存点,就是回滚到什么状态下 )
举例代码:
set autocommit=0; //关闭自动提交
start transaction; //开启事务,这一句写不写都可以,上面那一句也是开启事务的意思
delete from student where id =3; //操作代码
savepoint a; //设置保存点,设置点的名字随便起
delete from student where id=4; //操作代码
rollback to a; //回滚到a状态
运行结果是执行完这个事务之后会把id=3那行数据删掉,因为回滚所以id=4 的那行数据不会被删掉!
如果把回滚点设置在第一个delete语句之前,那么回滚之后所有的数据都不会被删掉!