你在银行存了100元,现在你要把100元转给用户A,银行一查你还有钱,开始给A转钱,这时,转钱给A的操作还未完成,你又把钱转给B,银行一看,你银行账号还有钱,就又给B转钱。那乱套了....银行血亏
所以把你转给A,转给B这两件事分为两个事务。
事务可以保证在事务中所有的数据库操作要么全部成功,要么全部失败。
事务的特性,即ACID(原子性,一致性,隔离性,持久性),这篇文章就来聊一聊隔离性。
多个事务同时执行时,可能出现脏读,不可重复读,幻读,为了解决这些问题,出现了“隔离级别”
SQL标准的隔离级别分为:读未提交,读提交,可重复读,串行化
读未提交:别人未提交,我也能看到
读提交:别人提交了,我才能看到
可重复读:别人提交了,我也不看
串行化:我没改完,谁也看不见
在实现上,数据库里面会创建一个视图,访问时以视图的逻辑结果为准。
在“可重复读”隔离级别下,视图在事务创建时建立,整个事务存在期间都用这个视图。
在“读提交”隔离级别下,视图是在每个SQL语句开始执行的时候开始创建的。
“读未提交”隔离级别下,直接返回记录上的最新值。
“串行化”隔离级别下,直接用加锁的方式来避免并行访问。
可重复读的场景适用于哪些范围?
比如你有一个账户余额表,一个账单明细,你在对比看是否与本月账单一致时一定不希望有新的交易发生影响你,这个时候用“可重复读”,可以默认事务是静态的
事务隔离 的实现:
在MYSQL中,每条记录在更新的时候都会同时记录一条回滚操作。通过回滚操作,可以得到前一个状态的值。
比如1+1,变为2,继续2+1变为3,再3+1变为4
从4开始回滚,可以得到1,2,4几个值,同一条记录在系统中存在多个版本,这就是多版本并发控制(MVCC)
回滚日志也不能一直保留,什么时候删除呢?
系统会判断,当没有事务需要用到这些回滚日志时,回滚日志才删除。
什么时候不需要呢?
当系统里没有比这个回滚日志更早的read-view的时候。
回滚段可能非常耗费资源,所以尽可能避免使用长事务
长事务:长时间未提交的事务
事务的启动方式:
1.显示启动事务语句,begin或者start transaction,配套的提交语句是commit,回滚语句是rollback
2. set autocommit=0,这个命令将自动提交关闭。意味着执行SQL语句,事务启动,不会自动提交。这个事务持续到你主动执行
commit或者rollback语句,或者断开连接。
有的框架建立连接后,会默认执行 set autocommit=0,就导致了接下来的操作数据库都在事务中,如果是长连接,就导致了长事务。