1.事务有哪些特性?如果去保证?
一:事务应当具备四大特性,ACID
A:原子性。是指一组事务要么同时成功,要么同时失败,不能是成功几个,失败几个。最典型的应用就是银行转账,不能一个转成功,一个失败。
C:一致性。是指一组事务的数据前后状态要保持一致,且需要满足事先定义个规则。A有500,B有1000,他们之间相互转账,始终要保证最终一共是1500,这是一致性的一种体现。
I:隔离性。某个线程的事务操作,不会对其他线程造成影响,他们之间应该相互隔离起来。即使是多个线程修改同一条数据,在没有完成之间,都不应对其他线程可见。
D:持久性。凡是完成提交了的数据,都应该持久化起来,保证数据的安全性,防止数据丢失。在发生异常的时候可以用来帮助恢复数据。
A:MySQL是通过undo log日志的形式保证原子性。执行一组事务,每当有写操作,undo log都会进行记录数据的初始值和修改后的值,如果发生了错误,则会对执行了的sql语句进行相反操作。如插入,则删除。删除,则添加。当事务执行完成之后,不管是事务成功还是事务回滚,都会清除undo log日志。
C:数据的一致性是最重要的,我们需要通过保证其他三者的情况下,来保证数据的一致性。
I:MySQL数据库有给我们提供四种隔离方案,根据隔离方案的不同,分别都能解决不同的隔离性问题。
D:如果每次对数据库的操作都直接写进磁盘,或者每次都要去磁盘查找,这样磁盘IO成本,时间成本都会很高。MySQL给我们提供的方案就是Redo log日志。
具体执行时当有数据操作时,会先写到Redo log日志当中,Redo log再更新到内存中,MySQL在合适的时间,一般是空闲时候,批量同步到磁盘。
这里需要注意,Redo log是数据库引擎层的功能,需要与数据库service层的bin log做一些区分。
他们的区别是:
Redolog是InnoDB提供的,只能在InnoDB引擎使用。而binlog是service层的,所有引擎都能用。
Redolog是物理日志,它记录的是对某页数据做了什么修改。binlog是逻辑日志,它是以二进制的形式记录sql语句的原始逻辑。
Redolog支持crash-safe,而binlog不支持。
Redolog存储大小是有限的,达到最大之后会从头开始覆盖写。binlog没有大小限制,当文件达到一定大小后会切换到下一个继续写,不会覆盖以前的日志。
2.事务隔离级别?分别解决了什么问题?
MySQL数据库有四大隔离机制。
读未提交。没有提交的数据也可以被其他线程访问到。会出现脏读,不可重复读,幻读问题。
读已提交。只有提交了的数据才能被其他线程访问到。会出现不可重复读,幻读问题。
可重复读。会出现幻读问题。
串行化。能避免所有的读问题,但是带来的就是效率非常低,一般不选用。
MySQL数据库默认开启可重复读隔离机制。数据库给我们提供了间隙锁机制,通过它加行锁就能实现避免出现幻读问题。
3.数据库的读写问题有哪些?
数据库读问题
脏读:指A线程修改了数据库但是还没有提交,B线程读取到了A修改后的数据,这时A如果回滚了,那么B读到的就是一笔脏数据。
不可重复读:指A线程在修改数据的前B读了一次,在修改后又读了一次,前后读取到的数据内容不一致,就是不可重复读。
幻读:指A线程在增删数据前B读了一次,修改后又读了一次,前后读取到的数据条数不同,就是幻读。
数据库写问题
一类丢失更新:事务的回滚会覆盖另一个事务的更新,现在数据库都已避免了这个问题,不做讨论。
二类丢失更新:事务的提交覆盖另一个事务的更新。常见解决办法是通过悲观锁和乐观锁。
悲观锁:MySQL自带的有排他锁和共享锁。insert,update,delete默认都是用的排他锁,什么意思呢,就是说在一个操作没有完成之前,其他的线程都不能既不能对数据进行写,也不能读,必须等它释放了锁之后才能操作。这种锁可以避免幻读问题,可是也会带来效率低的问题。共享锁。如果都是读操作,则相当于无锁,如果有写操作则必须等待读完成
乐观锁:通过一个版本号对数据的操作进行控制,低于当前版本的统统不让修改。这种方式并不能完全解决读问题,但是效率非常高,也是常用的一种。
3.MySQL数据库的MVCC机制。
MVCC机制是InnoDB引擎独有的。意思是多版本并发控制。对高并发的情况下,效率会比锁机制更高。
MVCC最重要的三个概念:
首先要知道,在读未提交模式下,直接读最新值。而串行化则使用了排他锁,也无需MVCC。所以MVCC是InnoDB引擎中,针对读已提交和可重复度两种隔离级别下的。
隐藏列:在我们每一行的数据中,都会有三列隐藏列。分别是记录当前事务id,回滚指针,还有一个是如果没有主键才生成的,用来充当主键的作用。
ReadView:可读视图。会当当前所有活跃的事务拉到一起,创建一个ReadView,并给他们都分配一个事务id,id的大小决定了他们的执行顺序。当读写并行的时候,只能读取事务id小于等于自身的数据。说白了,ReadView决定了当前事务能够读取到undolog链中的哪一个版本。
undolog链:多个事务并行操作数据库的时候,会通过回滚指针把他们的操作串成一条链,每一次的操作就相当于是一个版本号。undolog决定了当前事务能看到的是什么数据。
大致的来说,ReadView决定了当前事务能去undolog链中读取哪个版本,undolog则提供了所有版本的记录,而隐藏列则记录了事务id和回滚指针,通过回滚指针去找到是读取的哪一个undolog链。
select是分为快照读和当前读。如果我们没有显示的申明,那么数据库默认的就是快照读。快照读就是MVCC。好处是读写不冲突,效率高,坏处就是可能会出现幻读,并且读取到的数据可能不是最新数据。而当前读则使用了锁机制,保证在它读的时候没有其他事务能对这条数据进行修改。好处是读到的数据是最新的,并且避免幻读,坏处则是效率低,如果是全表查询则会导致表锁。