Mysql 事物
对于一些转账问题,如果转账出现了错误,会造成钱财丢失时
有两种方式避免错误
方式一:
使用@@autocommit 方法控制,设置手动提交,如果成功则提交,如果失败则回滚
create table account(id int auto_increment primary key comment '主键ID',name varchar(10) comment '姓名',money int comment '余额'
)comment '账户表';
insert into account(id,name,money)values (null,'张三',2000),(null,'李四',2000);select @@autocommit;#自动提交的意思
set @@autocommit=0;#设置为手动提交select * from account where name='张三';
#--恢复数据
update account set money=2000 where name='张三'or name='李四';#--张三转账
update account set money=money-1000 where name='张三';程序出现报错...#--李四收钱
update account set money=money+1000 where name='李四';commit ;rollback ;
方式二:使用start transaction 用法和上述相同
#--转账操作
start transaction ;select * from account where name='张三';
#--恢复数据
update account set money=2000 where name='张三'or name='李四';#--张三转账
update account set money=money-1000 where name='张三';程序出现报错...#--李四收钱
update account set money=money+1000 where name='李四';#--提交事务
commit ;#--回滚事物
rollback ;
事务四大特性
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。(就如转账操作,总金额是不变的)
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。(数据库当中的数据是存储在磁盘当中的,永久的保留下来)
并发事物问题
脏读(Dirty Read)
- 含义:一个事务读取了另一个事务尚未提交的数据 。若未提交事务回滚,先读取的事务拿到的数据就是无效的。比如事务 A 修改某条记录但未提交,事务 B 此时读取了这条记录,若 A 回滚,B 读到的数据就和实际不一致
- 原因:
- 事务并发执行,一个事务更新数据未提交时,另一个事务就去读取 。
- 数据库事务隔离级别设置过低,如设置为
Read Uncommitted
(读未提交) ,允许事务读取其他事务未提交的数据。
- 解决方法:
- 设置事务隔离级别:调整为
Read Committed
(读已提交)、Repeatable Read
(可重复读)或Serializable
(串行化) ,避免读取未提交数据。 - 加锁:读取操作时使用行级锁或表级锁锁定数据,防止其他事务修改。
- 优化事务设计:缩短事务执行时长,减少脏读发生几率 。
- 设置事务隔离级别:调整为
不可重复读(Non - Repeatable Read)
- 含义:在同一个事务中,两次读取同一行数据,结果却不一致 。比如事务 A 先读取某行数据,事务 B 在期间更新或删除了该行数据,事务 A 再次读取时结果就不同了。
- 原因:
- 并发事务更新:一个事务读取数据后,另一个事务对同一行数据进行更新操作 。
- 并发事务删除:一个事务读取数据后,另一个事务对同一行数据进行删除操作 。
- 解决方法:
- 设置事务隔离级别:设为
Repeatable Read
或Serializable
,防止事务执行期间数据被其他事务修改或删除。 - 加锁:读取操作时使用行级锁或表级锁锁定数据。
- 优化事务设计:缩短事务持续时间,降低并发操作对数据的影响 。
- 设置事务隔离级别:设为
幻读(Phantom Read)
- 含义:在同一个事务中,两次执行相同条件的查询,结果集却不一致 。比如事务 A 先按条件查询出一些数据,事务 B 在期间插入或删除了符合条件的数据,事务 A 再次查询时结果集就变了。
- 原因:
- 并发事务插入或删除:一个事务查询数据后,另一个事务对相同条件的数据进行插入或删除操作 。
- 并发事务更新:一个事务查询数据后,另一个事务对相同条件的数据进行更新操作,使符合查询条件的数据发生变化 。
- 解决方法:
- 设置事务隔离级别:设为
Serializable
,可避免幻读,但性能开销较大。 - 使用行级锁或范围锁:查询时锁定数据,防止其他事务插入、更新或删除数据。
- 优化事务设计:缩短事务持续时间,降低出现幻读的可能性 。
- 设置事务隔离级别:设为