基本用法
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';
COMMIT;
ROLLBACK; -- 假设这里发生了错误,我们回滚事务
先开启事务,再执行相关的行为,如果执行顺利直接commit
如果执行过程报错则执行ROLLBACK回滚操作
四大特征
一致性细节:
就是事务执行的过程中,数据可从一个有效的状态变成另一个有效的状态,如果事务成功,数据库的状态必须是有效的,如果事务失败,那么就要进行回滚等操作,必须保证数据库的最终状态是有效的,不会出现数据损坏,这就是一致性的含义,当初对这个有效状态很不理解,感觉解释和没有解释区别不大,那这里就举一个反例说明:
假设有一个在线购物系统,其数据库包含商品信息和用户订单。其中,商品信息表包含商品ID、商品名称、库存数量等字段,用户订单表包含订单ID、用户ID、商品ID、购买数量等字段。
在这个系统中,存在一个事务,即用户购买商品的过程。该事务涉及两个关键操作:更新商品信息表中的库存数量(减少购买数量)和在用户订单表中插入新的订单记录。
然而,由于某种原因(如系统故障、网络问题或并发控制不当等),这个事务在执行过程中出现了问题。具体来说,商品信息表中的库存数量没有成功减少,但用户订单表中已经插入了新的订单记录。这导致数据库中的数据不一致:订单记录显示用户已经购买了商品,但商品信息表中的库存数量却没有相应减少。这种状态就是非一致性的表现,数据库的数据状态不对。
有人又说这不是用原子性来保障的嘛,是的没错,但一致性就是数据库事务的最终目的,原子性就是一致性的实现途径之一;
持久性:
就是当事务提交或者回滚后就一定会写入数据库的磁盘,对数据的改变是永久性的。
隔离性:数据库提供的四种隔离标准(RUC、RC、RR、串行化)
原子性实现的底层
当开启事务之后,每次执行一个sql语句,在undo log日志里面都会记录一个还原该操作的记录,最后没有提交的话就会将所有的还原sql语句执行 ;
持久性实现的底层
每次执行sql语句的时候会先在redo log日志里面记录该sql语句,然后往mysql的缓存buffer(内存)里面执行sql语句,buffer会最终写入磁盘里面完成数据的持久化,如果mysql突然宕机的话,buffer里面的数据就会消失了,此时就要用redo log重写保障了持久性. PS:buffer的存在是为了减少io操作的次数,buffer是一个数据页,当写满之后才会写入磁盘,而不是每一次dml操作都要写入磁盘,浪费资源
隔离性
一个事务所做的修改在最终提交以前,对其他事务是不可见的。隔离性也是为了保证业务数据的一致性的途径。(四个隔离级别)
隔离性主要体现在两个方面
- 写-写操作,可以通过行锁、表锁、间隙锁实现
- 写-读操作:通过MVCC实现(mvcc的四种隔离层级:read uncommitted、read committed、repeat read 、serialize)
并发事务会出现的三个问题
脏读:
读取的信息是另一个事物修改但还未提交的行为
A事务读到了B事务update但未提交的数据是因为update之后,数据虽然并没有持久化进入数据库在磁盘的位置,但数据库在内存中有缓存,所以A读到了,只有提交之后,数据才会写入硬盘。
不可重复读:
对同一条数据在不同的时间点的查询,查询结果有差异(因为其他事务在此期间对该条数据进行了update操作)
幻读:
不同时间点读出来的数据集不同(是数据的行数有差异多一行或者少一行,注意和不可重复读的区别,脏读是因为没提交,不可重复读是同条数据在两次读之间被update了,幻读是两次读之间发生了insert/delete)
并发问题的处理标准
为了防止以上情况的发生,有一下四种隔离机制:
四种级别,innodb默认的是RR(可重复读)
1.Read Uncommited
RU隔离级别:不加锁。
2.Read Commited(未提交的读不到,提交的就会被读到)
RC隔离级别下,普通的select都是快照读,使用MVCC实现。在每一次执行快照读时生成ReadView,在RC隔离级别下,加锁的select都使用记录锁,因为没有Gap Lock。
除了两种特殊情况 外键约束检査(foreign-key constraint checking)以及重复键检査(duplicate-key checking)时会使用间隙锁封锁区间。所以RC会出现幻读的问题。
3.Repeatable Read(两次读结果相同)
RR隔离级别下,普通的select使用快照读(snapshot read),底层使用MVCC来实现。仅在第一次执行快照读时生成ReadView,后续快照读复用。(例外:当两次快照读之间存在当前读,ReadView会重新生成,导致产生幻读)
在默认开启的RR下,手动加锁的 select(select … in share mode / select … for update)以及更新操作update, delete等语句使用当前读(current read), 底层使用记录锁、或者间隙锁、临键锁。innodb在默认的隔离级别RR下,采用next-key + MVCC去解决幻读问题的:
在查询加for update时,会用next-key + MVCC解决幻读问题,新的insert和update会阻塞
在查询不加for update时,会用MVCC解决幻读问题,新的insert和update不会阻塞
4.Serializable
Serializable 所有的select语句都会被隐式的转化为 select… in share mode,会和 update、delete 互斥。
总结:隔离机制是数据库的四种处理并发问题的标准,而在mysql中RR、RC是通过MVCC来实现的
标签:事务,隔离,幻读,数据库,update,解读,select From: https://blog.csdn.net/ansmallwhite/article/details/137102343