事务的四个特性:
原子性:要么成功要么失败,A给B转账,要么成功,要么失败。
隔离性:互不影响的操作,A给B转账,A给C转账。
一致性:数据的合理变化,A给B转账,A的钱少了,B的钱多了。
持久性:转账记录的保存。
注意:mysql的事务自动开启,在我们执行sql的时候,默认开启事务,完毕后默认提交。
事务的隔离级别
事务的隔离级别有四种,分别是
1.读未提交
2.读已提交
3.可重复读(默认)
4.串行化
1.读未提交(不严谨):
举例:A事务修改了数据,并未提交,B事务在读的时候就读到了修改后的数据,A可能改错了,B读到的数据不严谨,不准确。
2.读已提交(幻读,不可重复读,解决了读未提交的不严谨,但是一个事务里会出现两个数据结果)
举例:A事务修改了数据,把123修改为456,还未提交,B事务读取数据为123,此时A提交,B再次读取,值为456,B蒙圈了,我在一个事务里,读了两遍,两个值,请给我个完美的解释~~~~~
3.可重复读(解决幻读)
举例:B读取数据,值为123,A修改了数据并提交,B再次读取数据依然是123,只要B在一个事务里,值都不会改变,不论是不是有其他事务修改了值。
4.串行化(针对并发读写)
读读不影响,读写并发引发串行化,在一个事务修改数据的时候,其他事务阻塞等待,数据的强一致性,但是效率略低。
读已提交和可重复读在底层是如何实现的呢
?这里涉及到了并发版本控制Multi-Version Concurrency Control,简称MVCC,举例说明:
读已提交底层实现
我们每调数据后都有隐藏列,事务修改了数据后(并没有提交),产生事务id,很多事务都对该数据进行修改,则该条数据后面有多个事务id,即版本链,每一个事务修改都是一个版本,而且是并发的,所以叫做并发版本链。新事务在读取的时候,会产生一个ReadView,里面有个m_ids的数组,这里面存放的是该条数据所有已修改但并未提交的事务id,然后通过数组的事务id的比对,找到最近的已提交的数据,返回,这样便读取到了已提交的数据。
可重复读底层实现:
新事务首次访问数据获取m_ids中的事务id,即使此时又有了新的事务对数据进行修改,m_ids数组的值也不会变化,也就是说,只要在同一个事务里,**根据首次进来对比事务id找到的最新数据,就一直不会改变
**。
手动开启一个事务:
begin+sql+commit
保存点:
savepoint
使用:在我们修改大量数据的时候,回滚则全部取消修改内容,减少工作量,
我们可以在确保修改正确的前提下,不断的新增保存点,这样即使回滚,也只回滚一部分。
语法:
设置回滚点:savepoint 保存点名称
回滚:rollback 保存点名称