概述
TCL(Transaction Control Language),事务控制语言。
事务就是一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
例如在支付宝中转账,则数据库要同时完成一方收钱一方余额减少的操作,而不能对这两个操作只执行一部分,此时就需要用到TCL事务控制语言
因此事务的目的:保证数据的最终一致性
事务可以通过回滚操作保证执行单元是否全部执行或不执行
如果在一个事务中某一行语句出现异常,可以通过回滚使数据还原到事务开启之前的状态
事务的特性
事务共有四个特性(ACID)(面试题常考):
-
原子性(Atomicity):一个事务不可再分割,要么都执行要么都不执行。 原子性由undo log日志来保证,因为undo log记载着数据修改前的信息。 如我们要 insert 一条数据了,那undo log 会记录的一条对应的 delete 日志。我们要 update 一条记录时,那undo log会记录之前的旧值的update记录。 -
一致性(Consistency):一个事务执行会使数据从一个一致状态切换到另外一个一致状态,即数据总量不变。比如说转账之前两个的金额总数是2000,那么转账后还应该是2000。 -
隔离性(Isolation):一个事务的执行不受其他事务的干扰。 在事务并发执行时,要求内部的操作不能互相干扰。如果多个事务可以同时操作一个数据,那么就会产生脏读、重复读、幻读的问题。(类似多线程) 因此事务与事务间需要一定的隔离 MySQL提供了四种隔离级别 不同的隔离级别对事务之间的隔离性是不一样的,级别越高事务隔离性越好,但性能就越低 而隔离级别的底层实现是由MySQL的各种锁来实现的,只是它屏蔽了加锁的细节。 -
持久性(Durability):一个事务一旦提交,则会永久的改变数据库的数据。会将数据持久化在硬盘上 MySQL的持久性是由redo log 日志来保证,当我们要修改数据时,MySQL是先把这条记录所在的「页」找到,然后把该页加载到内存中,将对应记录进行修改。 redo log:为了防止内存修改完了,MySQL就挂掉了(如果内存改完后MySQL挂掉,那修改相当于就丢失了),因此MySQL引入了redo log,在redo log中记录这次在哪一页中做了什么修改,这样即使MySQL挂了,也可以根据redo log的内容来对数据进行恢复
存储引擎
MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如 MySQL 原生的 MyISAM 引擎就不支持事务,这也是 MyISAM 被 InnoDB 取代的重要原因之一。
可以通过show engines 来查看mysql支持的存储引擎。
在mysql中用的最多的存储引擎有:InnoDB ,MyISAM ,memory 等。其中InnoDB 支持事务,而MyISAM 、memory等不支持事务。
事务的创建
在MySQL中事务分为隐式事务和显式事务
隐式事务的创建没有明显的开始与结束标志,直接书写DML语句即可(每一条语句都是事务,会自动提交)
显式事务具有明显的开启与结束标志
事务手动提交中,在写了开启事务的语句后,执行完事务中的sql语句并不会被提交,此时数据不被永久修改,此时查询到的是临时数据
如果不提交事务,则会默认回滚
因此执行完事务需要执行回滚语句或提交事务语句
事务自动提交则会在执行完事务后自动提交新数据并永久改变数据库中的数据
- 开启事务:
start transaction;
开启事务后,再下面写SQL代码即可
- 回滚:rollback;
rollback;
- 提交事务:commit;
commit;
- 自动提交的设置:
set autocommit=0;
该命令会把这个线程的自动提交关掉。这样事务就启动后,并不会自动提交,直到主动执行commit或rollback或断开连接(自动回滚)。
如果不设置取消自动提交,因为mysql中事务默认提交(一条DML语句(增删改)就会提交一次事务),所以只要运行DML语句就会提交事务
因此开启事务前必须先设置禁止自动提交!
MySQL默认自动提交,而Oracle默认手动提交
事务的隔离级别
概述:
我们期望事务之间是相互独立隔离的,但是当不同事务操作同一批数据时则会引发一些问题,此时我们需要设置不同的隔离级别保证事务的隔离性(类似多线程的安全问题)
引发问题:
如果没有设置隔离级别,则可能引发的问题:
- 脏读:一个事务读取到了另外一个事务中未提交的数据
- 不可重复读(虚读):一个事务俩次读取到的数据不一致
- 幻读:一个事务DML了表中所有数据,此时另一个事务重新添加了一条数据,第一个事务查询不到自己对新数据的DML操作
四种隔离级别
-
read uncommitted:读未提交 允许读取未被提交的数据 此时会产生的问题: 脏读,不可重复读,幻读 -
read committed:读已提交 (Oracle默认) 即只能读到已提交的数据 此时会产生的问题:不可重复读,幻读 即可以解决脏读问题 -
repeatable read:可重复读 (MySQL默认) 为了保证这一级别,在一个事务执行期间,禁止其他事务对数据更新 同时对于事务T1和T2,T1修改了数据并提交了,而T2并没有提交,则T2查询到的是修改前的数据 此时会产生的问题:幻读 -
serializable : 串行化 可以解决所有问题
Oracle 只支持的俩种事务隔离级别:read committed和repeatable read
查询与设置隔离级别
查询隔离级别:
select @@tx_isolation
设置隔离级别:
-- 设置当前mysql连接的隔离级别
set transaction isolation level 隔离级别
-- 注:每启动一个 mysql 程序, 就会获得一个单独的数据库连接
-- 上述方法只能更改当前连接的级别
-- 设置数据库系统全局的隔离级别
set global transaction isolation level 隔离级别;
-- 设置完重启软件或关闭cmd窗口后才会生效
|