MySQL(10):MySQL中的事务

事务

一、事务的概念

事务(Transaction) 是一种机制,是一个最小执行单元,可以由一个或多个SQL语句组成。在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功,只要有一个SQL语句执行失败,整个事务就都执行失败,因此事务是一个不可分割的工作逻辑单元。


二、事务的特性(ACID

(1)、原子性(Atomicity)

​ 事务的各个元素是不可分的,事务是作为一个整体提交或回滚,要么全部成功,要么全部失败。

(2)、一致性(Consistency)

​ 事务执行的前后,要保持数据的完整性和一致性。

(3)、隔离性(Isolation)

​ 各个事务之间是互相隔离的,互不干扰。

(4)、持久性(Durability)

​ 一旦事务被提交,事务对数据所做的任何变动都会被永久地保留在数据库中。


三、事务的原理

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


四、事务并发问题(读问题)

(1)、脏读

​ A事务读取了B事务未提交的更改数据

​ 意思是:B事务更新了一份数据,此时A事务读取了这一份更新的数据,由于某种原因B事务回滚了,所以A事务读取的数据是"脏数据"。

时间转账事务A取款事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4取出500元,余额500元
T5查询账户余额为500元
T6回滚事务,余额恢复1000元
T7转入100元,余额600元
T8提交事务
(2)、不可重复读

​ A事务读取了B事务已提交的更改数据

​ 意思是:同一个事务中,前后两次查询的数据不一致,原因是在两次查询数据之间,有另外一个事务对该数据进行了更新并提交了。

时间取款事务A转账事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4查询账户余额为1000元
T5转出500元,余额500元
T6提交事务
T7查询账户余额为500元
(查询的结果和T4不一致)
(3)、幻读

​ A事务读取了B事务已提交的新增数据

​ 意思是:同一个事务中,前后两次查询的数据笔数不一致,原因是在两次查询数据之间,有另外一个事务新增了(或者删除了)几条数据,并提交了。

时间统计金额事务A转账事务B
T1开始事务
T2开始事务
T3统计账户余额为1000元
T4新增一个存款账户,存款500元
T5提交事务
T6查询账户余额为1500元
(幻读/虚读)

详细参考事务并发问题


五、丢失更新(写问题)

(1)、第一类丢失更新

​ A事务回滚时,把已经提交的B事务的更新数据覆盖了。(回滚丢失)

时间取款事务A转账事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4查询账户余额为1000元
T5转入500元,余额1500元
T6提交事务
T7取出500元,余额500元
T8回滚事务
T9余额恢复1000元(回滚丢失了500元)
(2)、第二类丢失更新

​ A事务覆盖B事务已经提交的数据 ,造成B事务所做操作丢失。(覆盖丢失)

时间转账事务A取款事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4查询账户余额为1000元
T5取出500元,余额500元
T6提交事务
T7转入500元
T8提交事务
T9余额为1500元(覆盖丢失,银行亏了500)

六、事务的隔离级别

√:已解决

×:未解决

隔离级别脏读不可重复读幻读
读未提交(READ UNCOMMITTED)×××
读已提交(READ COMMITTED)××
可重复读(REPEATABLE READ)×
串行化(SERIALIZABLE)

从上到下,隔离级别越来越大。隔离级别越大安全性越高,同时效率也越低。

Oracle、SQL Server 默认隔离级别是读已提交,Mysql的默认隔离级别是可重复读。

MySQL实际工作使用读已提交

所有隔离级别都不允许第一类丢失更新发生。解决丢失更新的办法就是加锁。

悲观锁:(多写场景)

​ 认为多个事务更新操作一定会发生丢失更新。总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。

悲观锁的实现:

  1. 传统的关系型数据库使用这种锁机制,比如行锁、表锁、读锁、写锁等,都是在操作之前先上锁。
  2. Java里面的同步 synchronized关键字的实现。

悲观锁的分类:

  • 共享锁(shared locks):读锁,简称 S 锁。共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。

  • 排他锁(exclusive locks):写锁,简称 X 锁。如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,其他锁包括共享锁和排他锁。获取排他锁的事务可以对数据行读取和修改。

​ mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select ...for update语句,加共享锁可以使用select ... lock in share mode语句。

乐观锁: (多读场景

​ 认为多个事务更新操作不一定会产生丢失更新。总是假设最好的情况,每次读取数据的时候都认为不会有其他线程会更改数据,但在更新前需要判断一下在此期间有没有其他线程对数据进行了更改。

乐观锁的实现

  • 版本号控制

    一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值与当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

  • CAS 实现

    compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

    • 需要读写的内存值 V
    • 进行比较的值 A
    • 拟写入的新值 B

​ 当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

七、MySQL中事务简单使用

#1、开启事务
start transaction;#开启事务机制
set autocommit=0;#关闭自动提交
set autocommit=1;#开启自动提交


#2、编写一组逻辑sql语句
注意:sql语句支持的是insertupdatedelete

[设置回滚点,可选项]
savepoint 回滚点名;

#3、结束事务
提交:commit;
回滚:rollback;
回滚到指定的地方: rollback to 回滚点名;
撤销回滚点: RELEASE SAVEPOINT 保存点名;

银行转账案例:

#A 账户给 B 账户转账。
#1.开启事务
START TRANSACTION;|setAutoCommit=0;#禁止自动提交 setAutoCommit=1;#开启自动提交
#2.事务内数据操作语句
UPDATE ACCOUNT SET MONEY = MONEY-1000 WHERE ID = 1;
UPDATE ACCOUNT SET MONEY = MONEY+1000 WHERE ID = 2;
#3.事务内语句都成功了,执行 COMMIT;
COMMIT;
#4.事务内如果出现错误,执行 ROLLBACK;
ROLLBACK;

注意:开启事务后,执行的语句均属于当前事务。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值