数据库事务篇

事务原理

1)什么是事务

  • 事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全部都失败。
  • 事务作用:保证在一个事务中多次SQL操作要么全部成功,要么全都失败。

2)事务基本特性

(ACID,是针对单个事务的一个完美状态)

  • 原子性(Atomicity) : 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发送,要么都不发生
  • 一致性(Consistency) :事务前后数据的完整性必须保持一致。保持一致性的工具:锁
  • 隔离性(Isolation) : 事务的隔离性是指多用户的并发访问数据库时,一个用户的事件不能被其他用户的事务所干扰,多个并发事务之间数据互相隔离,隔离性由隔离级别保证!
    • 正常情况下数据库是做不到完完全全的隔离,可以增强隔离级别,但是效率会非常底。
    • read uncommitted -> read committed -> repeatable read -> serializable 【Mysql默认隔离级别RR】
      • 事务并发问题:脏读、不可重复读、幻读
      • 丢失更新的问题!
    • MVCC:multiple version concurrency control(多版本并发控制)
  • 持久性 :(Durability) : 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其他任何影响。

3)事务并发问题【事务隔离不足导致

如果不考虑隔离性,事务存在3中并发访问问题。

  1. 脏读:一个事务读到了另个一个事务未提交的数据
  2. 不可重复读:一个事务读到了另一个事务**已经提交(update)**的数据。引发另一个事务,在事务中的多次查询结果不一致。
  3. 虚读/幻读:一个事务读到了另一个事务已经**插入(insert)**的数据。导致另一个事务,在事务中多次查询的结果不一致。

4)事务隔离级别

数据库规范规定4种隔离级别,分别用于描述两个事务并发的所有情况。

  • read uncimmitted 读未提交,一个事务读到另一个事务已经提交的数据。
    • 存在:3个问题 (脏读、不可重复读、幻读)
    • 解决:0个问题
  • read committed 读已提交,一个事务读到另一个事务已经提交的数据。
    • 存在:2个问题 (不可重复提交、幻读)
    • 解决:1个问题 (脏读)
  • repeatable read 可重复读,在一个事务读到的数据保持一直,无论另一个事务是否提交。
    • 存在:1个问题 (幻读)
    • 解决:2个问题 (脏读、不可重复读)
  • serializable 串行化 同时只能执行一个事务,相当于事务种的单线程。
    • 存在:0个问题
    • 解决:3个问题 (脏读、不可重复读、幻读)

安全和性能对比

  • 安全性:serializable > repeatable read > read committed > read uncimmitted
  • 性能:serializable < repeatable read < read committed < read uncimmitted

常见数据的默认隔离级别:

  • Mysql:repeatable read

  • Oracle:read committed

手动提交

核心SQL语句
开始事务:start transaction
提交事务:commit
回滚事务:rollback
实现过程
第一步:开启事务
第二步:执行你的SQL语句
第三步:提交事务

事务案例

# 账户表
CREATE TABLE bankCount (
	id int PRIMARY key auto_increment,
	name VARCHAR(50),
	money double
);

# 添加数据
insert into bankCount (name, money) VALUES ("ttw", 1000), ("qz", 2000);

#查看当前事务的隔离级别 - 当前会话的
SELECT @@tx_isolation;
#查看当前事务的隔离级别 - 全局的
SELECT @@global.tx_isolation;

#修改当前会话的隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
#修改全局的隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  • 设置数据库的隔离级别
    • set session transactionisolation level 级别字符串
    • 级别字符串:READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE
  • 读未提交:READ UNCOMMITTED
事务A事务B
设置B事务隔离级别【读未提交】设置B事务隔离级别【读未提交】
开始A事务开始B事务
查询
更新数据
再次查询:查询到B未提交数据【脏读】
回滚
再次查询:B未提交数据消失
A事务提交【必须提交否则会对次测试产生影响】B事务提交

事务A

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

# 开启事务
START TRANSACTION;

SELECT * FROM bankCount;

# 脏读、不可重复读
# 当事务B执行后 B并未提交,但是A事务查询到的是B未提交的

# 提交事务 - 不提交会对下次测试产生影响,下次测试就不会有相同效果了。
COMMIT;

事务B

# 查看会话事务
SELECT @@tx_isolation;
# 设置会话事务
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# 开启事务
START TRANSACTION;
SELECT * FROM bankCount;
UPDATE bankCount SET money=money+500 WHERE name='ttw';

# 回滚
ROLLBACK;

# 提交事务
COMMIT;
  • 读已提交:read committed
事务A事务B
设置A事务隔离级别【读已提交】设置A事务隔离级别【读已提交】
开始A事务开始B事务
查询
更新数据
再次查询:数据没变,解决脏读问题
B事务提交
再次查询:数据没变,存在不可重复读问题
A事务提交

事务A

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

SELECT @@tx_isolation;

# 开启事务
START TRANSACTION;
# 当再事务B中更改数据后 事务B可以查到为提交的事务A则查不到未提交的事务
SELECT * FROM bankCount;

事务B

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

SELECT @@tx_isolation;

# 开启事务
START TRANSACTION;

SELECT * FROM bankCount;
# 更新数据库bankCount的表数据
UPDATE bankCount SET money=money+500 WHERE name='ttw';
SELECT * FROM bankCount;

# 为提交的情况 ↑

# 提交事务 - 事务A就可以查到了
COMMIT;
  • 可重复读:REPEATABLE READ
事务A事务B
设置A事务隔离级别【可重复读】设置B事务隔离级别【可重复读】
开始A事务开始B事务
查询
更新数据
再次查询:数据没变,解决脏读问题
B事务提交
再次查询:数据没变,解决不可重复读问题
A事务提交

事务A

SELECT @@tx_isolation;

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

# 开启事务
START TRANSACTION;

SELECT * FROM bankCount;

# 没提交前是读不到最新数据的

# 提交之后就可以读到新的数据了
COMMIT

事务B

SELECT @@tx_isolation;

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

# 开启事务
START TRANSACTION;

SELECT * FROM bankCount;

# 更新数据库bankCount的表数据
UPDATE bankCount SET money=money+500 WHERE name='ttw';

COMMIT
  • 串行话:SERIALIZABLE
事务A事务B
设置A事务隔离级别【串行化】设置B事务隔离级别【串行化】
开始A事务开始B事务
查询
更新数据-提示等待,如果A没有进一步操作B将等待超时
A事务提交或回滚
B等待结束,执行操作
B事务提交
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

# 开启事务
START TRANSACTION;

SELECT * FROM bankCount;

COMMIT
# 开启事务
START TRANSACTION;

# 更新数据库bankCount的表数据
UPDATE bankCount SET money=money+500 WHERE name='ttw';

# 只有事务 A 提交了 事务B才能更新或者查询
SELECT * FROM bankCount;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值