数据库存储引擎
MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。
MySQL中MyISAM与InnoDB的区别
InnoDB支持事务,MyISAM不支持事务。 InnoDB支持行级锁,MyISAM支持表级锁。 InnoDB支持MVCC, MyISAM不支持。 InnoDB不支持全文索引,MyISAM支持。 通过以上区别总结出:
InnoDB: 数据可靠性要求比较高,支持事务,适合表更新和查询比较频繁的场景
MyISAM:适合插入不频繁,查询频繁的场景
数据库ACID 为了保证数据库事务的正确性提出来的一个理论
原子性(Atomicity):事务中的操作是一个不可分割的整体单元,要么全部都做,要么全部不做。 一致性(Consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态 隔离性(Isolation):事务的结果只有提交了其他事务才可见 持久性(Durability):一旦事务提交完成,修改就是永久的,即使服务器宕机也不会影响到。
MySQL 事务 事务就是一组原子性的sql,是一个独立的工作单元。
我们可以通过设置 AUTOCOMMIT 变量来启动或则禁用自动提交模式。 设置1表示启用AUTOCOMMIT,0表示禁用AUTOCOMMIT。
MySQL中默认的是采取自动提交模式(AutoCommit),
只要不是显示的开启一个事务,每个查询操作都被当做一个事务执行提交的操作。 显示的开启一个事务开启,当用户执行commit命令时当前事务提交。从用户执行start transaction命令到用户执行commit命令之间的一系列操作为一个完整的事务周期。若不执行commit命令,系统则默认事务回滚。 事务并发带来的数据问题
隔离级别(isolation level),是指事务与事务之间的隔离程度,事务之间的隔离级别不同,会引发下面不同的问题
Read Uncommitted(未提交读、脏读):在该隔离级别,所有事务可以看到其他未提交事务的执行结果 。读取未提交的数据,也被称之为脏读(Dirty Read)。 Read Committed(提交读、不可重复读):一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持不可重复读,同一事务的其他实例在该实例处理其间可能会有新的 commit,所以同一 select 查询可能返回不同结果 Repeatable Read(可重复读、幻读)MySQL的默认事务隔离级别( MVVC的简单介绍 ) ,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,但插入的时候却却提示已经存在了,这就是幻读 (不可重复读描述的侧重点是修改操作,而幻读描述的侧重点是添加和删除操作 ) Serializable(可串行化)这是最高的隔离级别,它强制事务都是串行执行的,使之不可能相互冲突 ,从而解决幻读问题。换言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。 MVVC 实现原理介绍 MVCC(multiple-version-concurrency-control)是个行级锁 的变种,它在普通读情况下避免了加锁操作, 对于写操作只锁定必要的行
InnoDB 实现MVCC,是通过ReadView + Undo Log
实现的,Undo Log 保存了历史快照 ,ReadView可见性规则帮助判断当前版本的数据是否可见。
快照读 : 读取的是记录数据的可见版本(有旧的版本)。不加锁 ,普通的select语句都是快照读,如:
select * from user where id = 1;
当前读 :读取的是记录数据的最新版本,显式加锁的都是当前读
select * from user where id = 1 for update;
select * from user where id = 1 lock in share mode;
MVVC 的一些概念
事务版本号: 事务每次开启时,都会从数据库获得一个自增长的事务ID隐藏字段:每行记录都有两个隐藏列 trx_id :记录对应的事务 id roll_pointer: 数据的版本链,通过这个可以找到旧的数据 undo log:回滚日志,存储的是老版本数据。 在表记录修改之前,会先把原始数据拷贝到 undo log 里,如果事务回滚,即可以通过 undo log 来还原数据。或者如果当前记录行不可见,可以顺着undo log链找到满足其可见性条件的记录行版本ReadView :保存了当前事务开启时所有活跃的事务列表,ReadView 保存了不应该让这个事务看到的其他事务 ID 列表,查询时需要根据这个进行条件判断
如何查询一条记录 获取事务自己事务ID,即trx_id。(这个也不是select的时候获取的,而是这个事务开启的时候获取的 也就是begin的时候) 获取ReadView(这个才是select的时候才会生成的) 数据库表中如果查询到数据,那就到ReadView中的事务版本号进行比较。 如果不符合ReadView的可见性规则, 即就需要Undo log中历史快照,直到返回符合规则的数据;
参考博客 MVVC原理详解
深入理解 MySQL 锁-事务-并发