目录
[(2) 关掉 / 打开自动提交](#(2) 关掉 / 打开自动提交)
1、什么是事务?
事务这个概念的提出,是为了解决一个问题。
什么问题?
数据库是一个给上层用户提供疏通处理服务的实体
由此,不可避免的,会有多个用户同时对数据库有需求,即同时访问
同时访问,就会有并发的情况
同时访问,就会产生冲突和相关问题
举一个例子:
火车票购票系统
会出现很多人同时买票的场景
现在假设,数据表示A车厢,只有一张票
但是,现在有100个人在同时买这个车厢的票
现在,甲买了票,显示成功
按理说,剩余的其他人,将无法买到这张票
但是,票数-1的操作,数据库没有及时更新
于是,现在问题来了:
剩余的人,都发现仍然有一张票存在
既然有票,那就买
于是,明明只有一张票,却卖出了100份!
这事情就大了
事实上,由于数据库CURD对数据库和数据表的属性性质
其本身仅仅是操作和修改,并不能保证数据的安全访问和原子性的问题
所以,有问题!需要解决。
如何解决?
事务来解决。
那么,什么是事务?
事务就是一组DML语句组成的整体,要么成功,要么失败。
理解事务要从用户的需求去看
而不是站在程序员的技术角度
例如,转账100的数据库实现,
肯定是A的账户+100,B的账户-100
数据库的语句,应当是两句话,而不是一句话
但是,对于用户来说,转账的实现,应该是一个整体
用户不关心那个+100,那个-100
所以,对于用户来说,转账,就是一个事务
一个天然就应该是整体的事情
这,就是事务
所以,现在回到程序员的视角来看
事务,就是完成用户一个事情整体逻辑的多个语句的封装。
为什么会出现事务?
本质是为了当应用程序访问数据库时,
事务能够简化我们的编程模型
让程序员 / 上层不用去考虑各种并发问题和错误
所以,事务不是天生就有的
而是为了更好让上层使用数据库
让上层程序员不用关心底层细节
2、事务的特点
原子性 (Atomicity)
定义: 原子性确保事务中的所有操作要么全部成功,要么全部失败。如果事务中的任何一个操作失败,系统会回滚(rollback)到事务开始前的状态,确保数据库不会进入一个不一致的状态。
理解: 可以将原子性理解为"要么全部完成,要么全不做"。例如,在转账操作中,如果从一个账户扣款成功,但向另一个账户存款失败,则整个转账事务将回滚,确保两个账户的状态不变。
- 一致性 (Consistency)
定义: 一致性确保在事务开始前和结束后,数据库的完整性约束保持不变。在执行事务时,数据的状态必须从一个一致性状态转变为另一个一致性状态。
理解: 例如,如果数据库有一个约束,确保账户余额不能为负数,那么在事务结束后,所有账户余额依然不能为负数。事务的执行不能破坏这种一致性。
- 隔离性 (Isolation)
定义: 隔离性确保并发执行的事务之间不会互相干扰。事务的执行结果在被提交之前对其他事务是不可见的。
理解: 例如,两个事务同时操作同一数据时,隔离性确保一个事务的操作不会被另一个事务看到,直到第一个事务提交完成。这是通过使用锁机制和隔离级别来实现的。MySQL支持多种隔离级别,包括:
读未提交 (Read Uncommitted): 事务可以读取其他未提交事务的数据。
读已提交 (Read Committed): 事务只能读取已提交的数据。
可重复读 (Repeatable Read): 在事务开始后,任何对数据的读取都将返回相同的数据,直到事务结束。
串行化 (Serializable): 最严格的隔离级别,强制事务串行执行,完全隔离。
- 持久性 (Durability)
定义: 持久性确保一旦事务提交,其结果是永久性的,即使系统发生崩溃或故障,已提交的数据也不会丢失。
理解: 例如,完成的交易记录将保存在数据库中,无法通过系统重启或崩溃而丢失。MySQL通过日志记录和数据备份机制来实现持久性。
3、事务相关操作
一定要将抽象具体化,具体化就可以被想象
(1)查看事务
cpp
show variables like 'autocommit';
(2) 关掉 / 打开自动提交
cpp
set autocommit = 0 / 1;
(3)启用事务
cpp
start transaction;
#从该语句开始以后的所有语句都属于同一个事务
cpp
begin;#启用事务
(4)记录节点
cpp
savepoint point1;
#每一次执行语句结束后,使用该语句,标记节点
(5)回滚
cpp
rollbacrk to point1;
#取消节点对应语句
#如果没有设置保存点,默认回滚到开始
cpp
rollback;
#取消所有事务操作
(6)提交事务
cpp
commit;
#事务一旦提交,无法回滚
4、事务异常
如果事务中间中断,遇到异常,没有完成,系统会自动回滚,即撤回所有操作。
但只要commit提交以后,数据就插入成功
我们原来写的所有的单mysql语句全部都是事务,只是开启了自动提交
对于innodb来说,每一句语句都会被封装成事务,自动提交
如果自动提交打开了,那该语句会被自动提交
如果没有打开,此时如果系统崩溃,回滚,语句操作被撤销
5、事务隔离性
(1)隔离级别
什么叫做隔离?
mysql是一个服务端,不可避免的要被许多客户端同时访问
那么当有一个事务在执行时,就要进行隔离,避免打扰冲突
因此要给正在执行的事务增加一个隔离,
同时根据事务的重要程度,区分隔离等级,即可以被干扰的程度
在事务处理中,隔离是必要的
运行中的事务,进行互相隔离
各自互不干扰,即隔离性
根据影响程度的不同,分配隔离级
四种隔离级别:
特点 | 描述 |
---|---|
原子性 | 事务被视为一个整体,要么全部完成,要么全部不做。即使在事务执行过程中发生错误,事务中的所有操作也会被撤回。 |
一致性 | 事务的执行将数据库从一个一致性状态转变为另一个一致性状态。确保在事务完成后,所有数据都满足定义的规则和约束。 |
隔离性 | 并发执行的事务彼此之间是隔离的,一个事务的执行不应受到其他事务的干扰。隔离级别可以调节事务的可见性。 |
持久性 | 一旦事务被提交,对数据库的修改将是永久的,即使系统崩溃,数据也不会丢失。 |
(2)查看隔离级别
cpp
select @@global.tx.isolaton;
(3)设置隔离级别
cpp
set session transation isolation level read commited;
(4)隔离级别:读未提交
A事务的语句,例如修改、插入、更新等执行
还没有提交,其他事务就可以看到A事务对应执行改变的表
就是,我A事务还没有结束,没有commit,其他事务就可以查看了
因此,也成为脏读
这种个理解级别很低,不推荐
(5)隔离级别:读提交
当前事务在执行的操作,其他事务不能看到
只有commit,提交之后,其他事务才能看到
这种隔离级别有一个问题,即不可重复读取
不可重复读:
事务在多次读取时查看到的数据可能不一样
因为在并发时间内,可能有其他事务对数据进行了修改操作
但是,这是不应该的,因为事务的一切操作应当是原子性的
因此,这种隔离级别也不是很高,不是很推荐
(6)隔离级别:可重复读
可重复读:和不可重复读相反
两个事务并发运行时,即使一个事务提交,也不影响另一个事务
即,一个事务在多次查看读取数据时,数据不会发生变动
隔离事实上是对数据进行枷锁完成的
(7)隔离级别:串行化
对所有的事务进行枷锁,串行化进行,就是同一个时间只能有一个事务运行
很安全,但是效率极低