什么是事务
1、事务是一个最小的不可再分的工作单元;
例如:银行转账业务,就是一个最小的业务单元
2、事务保证业务逻辑中的多条 SQL 语句要么全部执行,要么全部不执行;
例如:淘宝购买生成一件上衣和一天裤子的订单,付款时一定是裤子和衣服的付款都正常完成,这笔订单才算正常完成,不可能出现衣服付款完成,裤子付款失败的情况。
3、在 MySQL innodb 下,每一条语句都是事务;可以通过 set autocommit = 0; 设置当前会话手
动提交;;
为什么有事务
事务是将数据库从一种一致性状态转换到另一种一致性状态
什么是ACID
事务的四个条件(ACID):
-
原子性(Atomicity)
- 事务的所有DML语句要么全部成功,要么全部失败,不会再中间环节结束,如果事务再执行过程中发生错误,那么所有操作都必须回滚到事务启动时的状态,就像事务所有操作没有发生过一样。 一致性(Consistency)
- 事务的执行后必须保证数据库的完整性。所有的写入的数据必须符合预设规则,包含数据的精确性,串联性及后续数据库可以自发性地完成预定的工作。
- 例如:淘宝购买生成一件上衣和一天裤子的订单,裤子50.1元,衣服100.2元。精确性表现为卖家账户会有150.3元入账,同时买家账户会有150.3元出账,不会出现卖家入账150元,买家出账150.3元的情况;串联性表现为,先中买家账户扣款成功150.3元后,卖家账户才能入账150.3元成功。 隔离性(Isolation)
- 数据允许多个并发事务同时对其数据进行读取和修改操作,隔离性是为了防止多个并发事务执行时由于交叉运行导致数据不一致。 持久化(Isolation)
- 事务结束后,对于数据的修改是永久的,即时系统故障也不会丢失。
事务并发异常
-
脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个修改的数据
例如淘宝购买衣服A一次性购买1000件生成订单但是还没有支付(修改数据未提交),这时卖家后台看到了1000件订单A很高兴,就安排发货(使用修改数据),随后买房取消了订单,造成损失。
-
不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读
例如:卖家客服查询一款有1200件的库存的衣服A(事务1),同时衣服被一个买家下单并支付了1000件该款衣服A(事务2)。卖家客服再次查询200件库存A(事务1),这时卖家客服2次查询得到的结果不一致。
-
幻读:事务中一次读操作不能支撑接下来的业务逻辑;通常发生在一个事务中一次读判断接下来写操作失败的情况;
例如:例如:买家A要下单1000件A衣服的订单询问卖家客服是否有足够的货源,卖家客服查询一款有1200件的库存的衣服A,回复货源足够(事务1),同时衣服A被一个买家B下单并支付了1000件该款衣服(事务2)。买家A下单1000件时提示库存A货源不足(事务1),导致买家A的交易无法进行。
解决方案:隔离级别
其实隔离级别就是解决上述数据库问题的方案。
Mysql有四个隔离级别:读未提交(read uncommit),读已提交(read commit), 可重复读(repeatable read),系列化(Serializable)。Mysql默认为可重复读(RR)
READ UNCOMMITTED
读未提交;该级别下读不加锁,写加排他锁,写锁在事务提交或回滚后释放锁;
READ COMMITTED
读已提交;从该级别后支持 MVCC (多版本并发控制),也就是提供一致性非锁定读;此时读取操作
读取历史快照数据;该隔离级别下读取历史版本的最新数据,所以读取的是已提交的数据;
REPEATABLE READ
可重复读;该级别下也支持 MVCC,此时读取操作读取事务开始时的版本数据;
SERIALIZABLE
可串行化;该级别下给读加了共享锁;所以事务都是串行化的执行;此时隔离级别最严苛;
隔离级别和问题对照表
脏读 | 不可重复度 | 幻读 | |
---|---|---|---|
read uncommit | √ | √ | √ |
read commit | × | √ | √ |
repeatable read | × | × | √ |
serializable | × | × | x |