事务概念;
是指作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。mysql里只有innodb和NDB支持事务
事务特性:acid(酸)个特性
原子性Atomicity: 操作同时成功或同时失败,依赖undolog实现
一致性Consistency: 事务的执行的前后数据的完整性保持一致
隔离性Isolation: 事务之间是透明的(互相不可见);普通select会用MVCC实现,更新/删除/插入会用LBCC(加锁)实现
持久性Durability: 一旦事务提交,则其所做的修改就会永久保存到数据库中。崩溃恢复用redolog,和双写缓冲doube buffer write
双写缓冲:doublewrite buffer是InnoDB在tablespace上的128个页(2个区)大小是2MB。
先使用memcopy将脏数据复制到内存中的doublewrite buffer,之后通过doublewrite buffer再分2次,每次写入1MB到共享表空间,然后马上调用fsync函数,同步到磁盘上。使用双写缓冲只需少量信息记录到redolog,虽然IO多了些,但性能上有提升。
MVCC: 生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别(语句集或事务集)的一致性读取(MVCC),多版本并发控制(Multi Version Concurrency Control)
LBCC: 在读取数据前,对其加锁,阻止其他事务对数据进行修改(LBCC),基于锁的并发控制(Lock Based Concurrency Control)
事务并发造成的问题:本质就是读一致性问题和写一致性问题
读一致性:脏读、不可重复读、幻读
写一致性:脏写、丢失更新
脏读:一个事务读取到了其他事务未提交的数据造成读不一致;
如: 张三说还李四一万块,开启事务之后就将钱转给李四,然后打电话叫李四看钱到没,李四查看说到了,然后张三直接回滚事务(rollback),既事务内所有的操作都放弃,张三自己账户的钱没扣,却说已经还给李四了,李四再查看,发现自己的账户没有转入的钱,只能当冤大头了
不可重复读:一个事务读取到了其他事务已提交的更新或删除数据造成读不一致
update/delete
如: A,B两个事务同时访问数据库,B事务查询数据库发现A账户还有一万块钱,此时A事务购买了东西,账户被扣了五千元,B忘记了账户还有多少钱,再查看,发现卡上只有五千元了,这种情况就是不可重复读。
幻读:一个事务读取到了其他事务已提交的插入数据造成读不一致
如: A,B两个事务同时操作数据库中,A查询表发现还有10个记录,此时,B事务增加了两条,并提交了事务,A事务再查看发现多了两条记录,就感觉自己出现了幻觉一样,这个就是幻读。
脏写:一个事务修改了其他事务未提交的数据,其他事务回滚了,此时由于undo log日志中存放的是一开始的数据记录,那么其他事务回滚就会把这条数据回滚为最初的数据值,导致这个事务的修改无效
丢失更新:一个事务修改了其他事务未提交的数据,其他事务提交了,而事务之间并不知道,发生更新丢失。
针对这些问题提出解决方案,就是事务隔离级别:
隔离级别读写数据的时候是有对应的锁机制实现的。所以不会出现写一致性问题。
确切的说修改数据用到了排他锁保证修改时事务串行化,一个事务没法修改其他事务未提交的数据,所以你在mysql中开启两个事务同时操作一行记录的话其中一个事务的sql一定是阻塞的状态,不信可以试试。
Read Uncommitted(RU未提交读):事务未提交的数据对其他事务也是可见的,会出现脏读,未解决读一致性问题,读数据时未增加锁,在修改数据时增加行级写排它锁。
Read Committed(RC已提交读):一个事务开始之后,只能看到已提交的事务所做的修改.会出现不可重复读,解决了脏读。读取数据时增加行级共享锁,读取结束,立即释放,在修改数据时增加行级排它锁,直到事务结束才释放
Repeatable Read(RR可重复读,Mysq默认级别):在同一个事务中不会读取到其他事务提交的数据。可能出现幻读,但在mysql的innodb中RR实现基于ReadView机制同时避免了不可重复读和幻读。在数据读取时,增加行级共享锁,直到事务结束,在修改数据过程中,必须增加行级排它锁,直到事务结束才释放。
Serializable(S串行化):解决所有问题,强制事务的串行执行,通过隐式加共享锁实现即sql后追加lock in share mode,会和update、delete互斥。读取数据时,必须先增加表级共享锁,直到事务结束时才释放,修改数据时,必须先增加表级排它锁,直到事务结束才释放;