事务
TCL,事务控制语言:
事务概念:如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
事务:多条sql语句组成一个执行单元,这些sql语句要么全部执行成功,要么全部执行失败。比如转账:张三转账给李四,张三的金额要减少,李四的金额要增加,类似于这种操作,要么全部成功,要么全部失败,所以整个的单独的单元是不可以分割的整体,如果某条sql执行失败,则整个单元都执行失败,这种操作叫做事务的回滚。如果这个单元的每条sql都执行成功,那么则事务被提交。
事务:由单独单元的一个或多个sql语句组成,在这个单元中,每条mysql语句是相互依赖的。
而整个单独单元作为一个不可分割的整体,如果单元中某条sql语句一旦执行失败或产生错误,
整个单元将回滚,回滚后所有受到影响的数据将返回事务开始前的状态。
如果单元中所有的sql语句都执行成功,则提交事务。
mysql中的存储引擎:
1.概念:在mysql中的数据用各种不同的技术存储在文件(或内存)中。
2.通过SHOW ENGINES;来查看mysql支持的存储引擎。
3.在mysql中用的最多的存储引擎有:INNODB,MYISAM,MEMORY等。但只有INNODB支持事务。
事务的特点(事务的ACID属性):
1.原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生(成功),要么都不发生(失败)。
2.一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态。
#案例:姜建民向马鹏鹏转账20元。
update 表 set 余额 = 余额-20 where name = ‘姜建民’;
update 表 set 余额 = 余额+20 where name = ‘马鹏鹏’;
姜建民余额减少20,我的余额就增加20,不可能说就加1元,这就是一致性。
3.隔离性:事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作
及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4.持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,
接下来的其他操作和数据库故障不应该对其有任何影响。
1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
2. 一致性:事务操作前后,数据总量不变
3. 隔离性:多个事务之间。相互独立。
4. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
事务的使用:
事务的使用:
以第一个DML(增删改)语句的执行作为开始
以下面的其中之一作为结束:
COMMIT或ROLLBACK语句
DDL或DCL语句(自动提交)
用户会话正常结束
系统异常终止
隐式事务:没有事务明显的开始和结束语句。
比如在mysql中进行的任何增删改操作。
显示事务:事务有明显的开始和结束标记。
1.前提:必须关闭事务的自动提交。 【SHOW VARIABLES LIKE '%commit%';查看系统变量】
set autocommit = 0; 关闭事务的自动提交。
2.开启事务: 【任何一条DML(增删改)语句的执行都可视为事务的开启】
start transaction; #开启事务
3.编写事务中的sql语句(一组sql语句,如insert,update,delete)
4.结束事务。
commit; 提交事务,数据更新成功。
rollback; 回滚事务,数据还原为回滚前状态,回滚是从下往上。
MySQL数据库中事务默认自动提交
* 事务提交的两种方式:
* 自动提交:
* mysql就是自动提交的
* 一条DML(增删改)语句会自动提交一次事务。
* 手动提交:
* Oracle 数据库默认是手动提交事务
* 需要先开启事务,再提交
* 修改事务的默认提交方式:
* 查看事务的默认提交方式:SELECT @@autocommit; -- 1 代表自动提交 0 代表手动提交
* 修改默认提交方式: set autocommit = 0;
事务案例:姜建民向马鹏鹏转账20元。
CREATE DATABASE lianxi;
CREATE TABLE account(
a_id INT PRIMARY KEY AUTO_INCREMENT,
balance DOUBLE(10,2) DEFAULT 0,
a_name VARCHAR(20) NOT NULL
);
INSERT INTO account VALUES (1,100,'姜建民'),(2,100,'马鹏鹏');
# insert into account (balance,a_name) values (100,'姜建民'),(100,'马鹏鹏');
SELECT * FROM account;
#事务的操作:转账操作
SET autocommit = 0; #1.关闭事务的自动提交。
START TRANSACTION; #2.开启事务
#3.编写一组sql语句
UPDATE account SET balance = balance - 20 WHERE a_name = '姜建民';
UPDATE account SET balance = balance + 20 WHERE a_name = '马鹏鹏';
COMMIT; #4.提交事务
DELETE FROM account;
INSERT INTO account VALUES (1,100,'姜建民'),(2,100,'马鹏鹏');
SELECT * FROM account;
SET autocommit = 0; #1.关闭事务的自动提交。
START TRANSACTION; #2.开启事务
#3.编写一组sql语句
UPDATE account SET balance = balance - 20 WHERE a_name = '姜建民';
UPDATE account SET balance = balance + 20 WHERE a_name = '马鹏鹏';
ROLLBACK; #4.回滚事务
delete和truncate[不受事务的控制]在事务中的区别:
SET autocommit = 0; #1.关闭事务的自动提交。
START TRANSACTION; #2.开启事务。
#delete from account ; #回滚事务后,数据还原为删除之前的状态。
TRUNCATE TABLE account; #回滚事务后,数据删除了,数据没有还原删除之前的状态。TRUNCATE不受事务的控制。
ROLLBACK; #3.回滚事务
savepoint的使用,事务回滚到保存点:
SET autocommit = 0; #1.关闭事务的自动提交。
START TRANSACTION; #2.开启事务。
UPDATE account SET balance = balance + 20 WHERE a_name = '马鹏鹏';
SAVEPOINT a; #设置一个回滚保存点a
UPDATE account SET balance = balance - 20 WHERE a_name = '姜建民';
ROLLBACK TO a; #3.事务回滚到保存点a,回滚是从下往上。结果是马鹏鹏120,姜建民100。
数据库的隔离级别:
事务的隔离级别(面试常考):多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
存在问题:
1. 脏读:一个事务,读取到另一个事务中没有提交的数据
2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
脏读:针对update更新语句,脏读针对读取的第一次结果(回滚)
不可重复读:针对update更新语句,不可重复读针对读取的第二次结果
幻读:针对insert语句
对于并发运行的多个事务,当这些事务访问数据库中相同的数据的时候,如果没有采取必要的隔离机制,会导致事务并发的各种问题:
1.脏读:对于2个事务T1和T2,T1读取了已经被T2更新但还没有被提交的字段(数据)。
之后T2进行回滚,T1读取的内容就是临时且无效的。
2.不可重复读:对于2个事务T1和T2,T1读取了一个字段,然后T2更新了该字段,
之后T1再次读取同一个字段,值就不同了。
3.幻读:对于2个事务T1和T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的数据行,
之后T1再次读取同一个表,就会多出几笔数据。
数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使它们不会互相影响,避免各种并发问题。
一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱,效率越来越低。数据库提供了四种隔离级别:
四种事务隔离级别:(MySQL支持这四种事务隔离级别,oracle支持read committed和serializable)
1. read uncommitted:读未提交
* 产生的问题:脏读、不可重复读、幻读
* 可以读取其他事务未提交的数据,这时脏读、幻读和不可重复读一定会出现,这种隔离级别也是最低的隔离级别。
2. read committed:读已提交 (Oracle默认)
* 产生的问题:不可重复读、幻读
* 只允许读其他事务已经提交的数据,可以避免脏读,但是不可重复读和幻读依然会出现。
3. repeatable read:可重复读 (MySQL默认)
* 产生的问题:幻读
* 可重复读,确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他的事务对这个字段进行更新,可以避免脏读和不可重复读,但是幻读的问题依然会出现。
4. serializable:串行化
* 可以解决所有的问题
* 串行化,确保事务可以从一个表中读取相同的数据,在这个事务运行期间,禁止其他的事务对这个表的数据进行更新操作。
* 注意:隔离级别从小到大(1到4)安全性越来越高,但是效率越来越低。
* 说明:这里所说的更新指的是对数据的增删改操作 。
* 在这四个隔离级别中,Oracle只支持两种:read committed和serializable,Oracle数据库的默认的隔离级别是read committed,MySQL支持四种隔离级别,默认的是repeatable read。一般情况下,为了达到事务的高并发,而往往将数据库的隔离级别设置为较低的级别。
* 查询当前数据库事务隔离级别:
* select @@tx_isolation;
* 设置当前数据库的隔离级别:
* SET [SESSION|GLOBAL(如果不填,默认是SESSION)] transaction isolation level 隔离级别
* SET TRANSACTION ISOLATION LEVEL READ COMMITTED;-- 设置当前数据库的隔离级别
* SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;-- 设置全局数据库(所有数据库)的隔离级别