前言
- 一个事务通常对应着一个完整的业务,同时事务是不可再分的,是最小的工作单元
- 一个完整的业务需要批量的DML(insert,delete,update)语句共同联合完成
- 事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同。
实操
接下来通过实操了解一下什么是事务:
看一个转账业务,现在有张三李四二人都揣着100块钱。
我们利用两条update修改语句将张三的钱含泪转给李四。
注意:以上两条DML语句必须同时成功或者同时失败。这也是事务不可再分的含义,其中若有一个成功或者失败则相当于把它俩拆开来看,这是不对的。
区别于非事务提交即非事务提交无法保证业务同时成功或失败
如下:sql语句会执行第一条修改语句而第二条会报错
和事务相关的术语:
- 开启事务:start transaction
- 事务提交:commit transaction
- 事务回滚:rollback transaction
- 事务结束:end transaction
事务提交
start transaction;#开启事务
......sql语句......
commit;#事务提交
mysql如何实现事务
1.开启事务
2.事务提交/事务回滚
3.事务结束
什么是事务回滚?
即事务执行rollback语句回滚到原来的状态
注意:事务提交后进行回滚是不生效的,因为事务提交后事务的持久性就会起作用
例:对t_act进行提交和回滚操作
(1)提交操作(非事务成功)
(2)提交操作(非事务失败)
(3).提交操作(事务成功)
- start transaction #开始事务
- DML语句
- commit #事务提交
(4)提交操作(事务失败)
(5)回滚操作(事务失败)
事务在执行rollback语句回滚到原来的状态!
事务的四大特性(一定要理解!!!)
1.事务具有原子性:指一个事物是一个不可分割的工作单位,其中的操作要么都成功,要么都失败。(上文提到)
2.事务具有持久性:指事务一旦提交,他对数据库的改变就应该是永久性的,接下来的其他操作或故障不应该对其有任何影响。(就是张三给李四转账转了100块,张三想再拿回去已经不可能了(除非进行其他业务))
持久性问题的产生:
背景:Mysql为了保证存储效率,每次读写文件都是先对缓存池(BufferPool)操作缓冲池再定期刷新到磁盘中(这一过程称为刷脏)。
产生:由于数据不是直接写到磁盘,那么如果主机断电,就会有一部分数据丢失。
解决:通过重做日志(redo 1og)恢复数据。在每次修改数据之前,都会将相应的语句写到redo log中,如果主机断电,那么再次启动时可通过redo log回复。
拓展:redo log也需要在事务提交时将日志写入磁盘,它比缓冲池写入快的原因有两点:
redo log是追加文件写,属于顺序I0,缓冲池是属于随机I0,且刷脏是以页为单位,
有一点修改就要整页写入
3.事务具有隔离性:事务和事务之间是互相隔离的,各个事务之间不能互相干扰。而事务并发问题就是隔离性的问题
4.事务具有一致性:事务在执行之前和执行之后,数据库的状态必须保持一致。这意味着事务执行过程中的任何变化都必须满足预定的规则和约束。前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。
事务的并发问题
1.脏读:事务A读取到了事务B修改但未提交的数据
2.不可重复读:是指在一个事务内,多次读取同一数据,但是数据的值发生了改变
3.幻读:指的是在一个事务中,多次查询同一个范围的数据,却发现有新增或者减少的行。这是因为在这个事务进行的过程中,另一个事务插入或者删除了符合查询条件的数据,导致前后两次查询结果不一致。
总结不可重复读和幻读的区别:
五、事务的隔离级别
mysql中的四种事务隔离级别如下:
1.read uncommitted (读未提交数据):允许事务读取未被其他事务提交的变更。(脏读、不可重复读和幻读的问题都会出现)
#设置读未提交的隔离级别
set global transaction isolation level read uncommitted;
#查看当前隔离级别
select @@global.tx isolation,@@tx isolation;(旧版本)
SELECT @@global.transaction_isolation, @@transaction_isolation;(5.7.20版本之后)
2.read commited(读已提交数据):只允许事务读取已经被其他事务提交的变更。(可以避免脏读,但不可重复读和幻读的问题仍然可能出现)
#设置读以提交的隔离级别
set global transaction isolation level read committed;
插入但是没有提交,是读不出来的,提交之后才能够读出来
3.repeatable read(可重复读):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新(update)。(可以避免脏读和不可重复读,但幻读仍然存在)
#设置可重复读的隔离级别
set global transaction isolation level repeatable read;
可见,无论是删除还是添加,commit后都是成功的,但是另一边却还是读出原来的数据,这就是可重复读,读取的是备份数据不是真正的数据。
4.serializable(串行化):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可避免,但性能十分低下(因为你不完成就都不可以弄,效率太低)
#设置串行化的隔离级别
set global transaction isolation level serializable;