TCL事务控制语句
事务属于TCL控制语言(Transaction Control Language )。
一. 事务概述
1.1 什么是事务?为什么要用事务?
一个事务是由一条或者多条sql语句构成,这一条或者多条sql语句要么全部执行成功,要么全部执行失败!
默认情况下,每条单独的sql语句就是一个单独的事务!
举例:
银行转账!张三转10000块到李四的账户,这其实需要两条SQL语句:
给张三的账户减去10000元;
给李四的账户加上10000元。
如果在第一条SQL语句执行成功后,在执行第二条SQL语句之前,程序被中断了(可能是抛出了某个异常,也可能是其他什么原因),那么李四的账户没有加上10000元,而张三却减去了10000元。这肯定是不行的!
你现在可能已经知道什么是事务了吧!事务中的多个操作,要么完全成功,要么完全失败!不可能存在成功一半的情况!也就是说给张三的账户减去10000元如果成功了,那么给李四的账户加上10000元的操作也必须是成功的;否则给张三减去10000元,以及给李四加上10000元都是失败的!
1.2 MySQL中的存储引擎
**1、存储引擎的概念:**在mysql中的数据用各种不同的技术存储在文件(或内存)中。
**2、通过show engines;**来查看mysql支持的存储引擎。
3、 在mysql中用的最多的存储引擎有:innodb, myisam ,memory 等。其中innodb支持事务,而
myisam、memory等不支持事务。
二.事务的分类
1.隐式事务:没有明显的开启和结束标记,比如dml语句的insert、update、delete语句本身就是一条事务
insert into stuinfo values(1,'Jack','男','123@qq.com',12);
2.显式事务:具有明显的开启和结束标记,一般由多条sql语句组成,必须具有明显的开启和结束标记
步骤:
1、开启事务
取消隐式事务自动开启的功能
2、编写事务需要的sql语句(1条或多条)
-- insert into stuinfo values(1,'Mark','男','123@qq.com',12);
-- insert into stuinfo values(2,'Lisa','女','123@qq.com',12);
3、结束事务
提交事务或回滚事务
三.事务的四大特性(ACID)
原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
一致性(Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。
隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
总结:
-- 原子性(Atomicity):指在事务中包含所有操作,要么都做,要么都不做(不可分割)
-- 一致性(Consistency):数据的改变保证一致
-- 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,防止多个事务并发执行时由于交叉执行而导致数据的不一致。
-- 持久性(Durability):事务处理结束之后,对数据的修改是永久的,即便你的系统出现故障,也不会丢失。(将数据存在了磁盘上)
四.MySql中的事务
在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。
-- 开启事务:start transaction;
-- 结束事务:commit或rollback;
-- 断点 savepoint 断点 rollback to 断点
在执行SQL语句之前,先执行strat transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了。
由于事务是自动开启的,需要先取消事务的自动开启
-- 查看含有auto的变量
SHOW VARIABLES LIKE '%autocommit%'
-- 取消事务自动开启
SET autocommit = 0;
案例:
创建事务要用到的表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
balance double(10,2)
);
INSERT INTO account(NAME,balance) VALUES('zs', 100000);
INSERT INTO account(NAME,balance) VALUES('ls', 100000);
SELECT * FROM account;
Ø 演示事务执行失败
-- 案例一:回滚 事务执行失败
START TRANSACTION;
UPDATE account SET balance=balance-10000 WHERE id=1;
UPDATE account SET balance=balance+10000 WHERE id=2;
ROLLBACK;
-- 案例二:退出mysql客户端 事务执行失败!
START TRANSACTION;
UPDATE account SET balance=balance-10000 WHERE id=1;
UPDATE account SET balance=balance+10000 WHERE id=2;
Ø 演示事务执行成功
START TRANSACTION;
UPDATE account SET balance=balance-10000 WHERE id=1;
UPDATE account SET balance=balance+10000 WHERE id=2;
COMMIT;
五.事务的隔离级别
5.1 事务并发问题如何发生?
当多个事务同时操作同一个数据库的相同数据时
5.2 事务的并发问题有哪些?
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
-- 多个事务同时处理,会遇到的现象:
脏读:用户读了修改后未提交的数据(rollback产生)
不可重复读:读取同一条记录,但是两次数据不一样(两次提交同一条记录)
幻读:读取同一张表,两次记录数不一样(两次提交不同的记录)
5.3 如何避免事务的并发问题?
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。 Oracle 默认的事务隔离级别为: READ COMMITED。
Mysql 支持 4 种事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ
-- 通过设置事务的隔离级别
读未提交READ UNCOMMITTED:允许幻读和不可重复读,脏读
读提交READ COMMITTED:允许幻读和不可重复读,但是不允许脏读
--读提交:本次操作若发生改变了,必须提交,其他人才能看见改变的(Oracle默认)
重复读REPEATABLE READ:允许幻读,但是不允许不可重复读和脏读(MySQL默认)
串行化读SERIALIZABLE:都不允许幻读和不可重复读,脏读
--串行化读:首先重新建立连接,只管自己本次事务操作,不管外部数据的变化(即使提交也看不见)
每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每 个数据库连接都有一个全局变量@@tx_isolation, 表示当前的事务隔离级别。
-- mysql中默认 第三个隔离级别 repeatable read
-- oracle中默认 第二个隔离级别 read committed
-- 查看当前的隔离级别
select @@tx_isolation;
-- 设置 当前会话 | 数据库系统的全局的 MySQL连接的隔离级别
set session|global transaction isolation level 隔离级别;
读未提交READ UNCOMMITTED:允许幻读和不可重复读,脏读
读提交READ COMMITTED:允许幻读和不可重复读,但是不允许脏读
重复读REPEATABLE READ:允许幻读,但是不允许不可重复读和脏读(MySQL默认)
不允许不可重复读和脏读
允许幻读