SQL - 事务控制

SQL - 事务控制

文章目录

  • SQL - 事务控制
    • TCL - 事务
      • 事务的边界
      • 事务的特性
      • 事务的应用
    • 事务隔离等级
      • MySQL支持四种隔离级别

TCL - 事务

**模拟场景:**生活当中转账是转账方账户扣钱,收账方账户加钱。用数据库操作来模拟现实转账。

数据库模拟:

  • A账户减1000元
UPDATE account SET MONEY = MONEY-1000 WHERE id=1;
  • B账户加1000元
UPDATE account SET MONEY = MONEY+1000 WHERE id=2;

思考: 假设在A账户减钱后,程序出现了异常,那B账户还会执行加钱操作吗?

每条SQL语句都是一个独立的操作,执行成功后对数据库是永久性的影响。

概念:

  • 事务是一个原子操作,由一个或多个SQL语句组成。
  • 在同一个事务当中,所有的SQL语句要么全部执行成功,要么全部失败。

原理:

  • 数据库会为每一个客户端都维护一个空间独立的缓存区(回滚段)。
  • 一个事务中所有的增删改语句的执行结果都会缓存在回滚段中。
  • 当事务中所有SQL语句均正常结束,才提交(commit),才会将回滚段中的数据同步到数据库。
  • 否则无论因为哪种原因失败,整个事务将回滚(rollback)。

事务的边界

**开始: **

  • 默认连接到数据库,隐式开始事务,每条语句执行完自动提交或回滚。
  • 手动使用begin; 或 start transaction; 显示开启事务,不会自动提交或回滚。
  • set autocommit=0; #禁止自动提交。

begin 和 set autocommit=0 的区别

SQL - 事务控制_第1张图片

结束:

  • 提交:
    • 显式提交:commit;
    • 隐式提交:一条DML语句,正常提交(客户端退出连接)。
  • 回滚:
    • 显式回滚:rollback;
    • 隐式回滚:非正常退出(断电、宕机)。执行了创建、删除的语句,但是失败了,会为这个无效的语句执行回滚。

事务的特性

1 Atomicity(原子性)

  • 表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败。

2 Consistency(一致性)

  • 表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态。

3 Isolation(隔离性)

  • 事务查看数据操作时数据所处的状态,要么是另一并发事务修改它之前的状态。
  • 要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。

4 Durability(持久性)

  • 持久性事务完成之后,它对于系统的影响是永久性的。

事务的应用

基于增删改语句的操作结果,可通过程序逻辑手动控制事务提交或回滚。

应用事务完成转账:

开启事务:
 begin;start transaction;
 set autocommit=0;#禁止自动提交 ,默认为1
事务内数据操作语句:
 UPDATE ACCOUNT SET MONEY = MONEY-1000 WHERE ID = 1;
 UPDATE ACCOUNT SET MONEY = MONEY+1000 WHERE ID = 2;
事务内语句都成功了,提交:
 commit;
事务内如果出现错误,回滚:
 rollback;

代码演示:

#创建表
create table account(
	id int primary key auto_increment,
	name varchar(20) not null,
	money decimal(12,2)
)charset=utf8mb4
#添加数据
insert into account values(null,'张三',10000),(null,'李四',0);
select * from account;

#显示开启事务 begin; 或 start transaction;
# begin;
set autocommit=0; #禁止自动提交
#转账
# 1 扣钱
update account set money=money-1000 where name='张三';
# 2 加钱
update account set money=money+1000 where name='李四';

#显示提交[成功]
commit;
#显示回滚[失败]
rollback;
set autocommit=1;#开启自动提交

事务隔离等级

操作:

  • select @@tx_isolation; #查看隔离级别
  • set session transaction isolation level [隔离级别] #修改隔离级别

MySQL支持四种隔离级别

1 Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,称之为脏读(Dirty Read)。

2 Read Committed(读取提交内容)

大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别出现不可重复读(Nonrepeatable Read)问题,因为同一事务的其他实例在该实例处理期间可能会有新的commit,所以同一select可能返回不同结果。

3 Repeatable Read (可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻读” 行。InnoDB和Falcon存储引擎通过多版本并发控制机制解决了该问题。

4 Serializable(串读)

最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。效率最低的。

代码演示:

#查看隔离级别, 默认隔离级别: REPEATABLE-READ 可重复读
select @@tx_isolation;
# 1 设置隔离为 read uncommitted 读取未提交, 问题: 脏读
set session transaction isolation level read uncommitted;

# 2 设置隔离级别为 read committed 读取提交, 问题: 不可重复读
set session transaction isolation level read committed;

# 3 设置隔离级别为 repeatable read 可重复读, 问题: 幻读 (MySQL没有)
# 开启事务后不被外界影响
set session transaction isolation level repeatable read;
# 需求: 统计每天的收入情况
BEGIN;
	select * from account where name = '李四'; 
	select * from account where name = '李四'; 
	select * from account where name = '李四'; 
	#入账
COMMIT;

# 4 设置隔离级别为 serializable 串读 没有问题, 但性能低
set session transaction isolation level serializable;

你可能感兴趣的:(从零学Java,sql,oracle,数据库)