目录
事务
MySQL事务的四大特性
ACID
原子性
持久性
隔离性
事务的隔离级别
读未提交
读已提交
可重复读
串行化
事务的隔离级别如何实现
MVCC
版本链
READVIEW
高可用
MySQL数据库的读写分离
主从复制
主从同步延迟怎么处理
分库策略
水平分库分表的策略
事务
MySQL事务的四大特性
事务是一条或多条 SQL 语句组成的执行单元。四个特性分别是原子性、一致性、隔离性和持久性。原子性保证事务中的操作要么全部执行、要么全部失败;一致性保证数据从事务开始前的一个一致状态转移到结束后的另外一个一致状态;隔离性保证并发事务之间互不干扰;持久性保证事务提交后数据不会丢失。
ACID
就是事务的四大特性
原子性
ACID 中的原子性主要通过 Undo Log 来实现,持久性通过 Redo Log 来实现,隔离性由 MVCC 和锁机制来实现,一致性则由其他三大特性共同保证。
事务对数据进行修改前,会记录一份快照到 Undo Log,如果事务中有任何一步执行失败,系统会读取 Undo Log 将所有操作回滚,恢复到事务开始前的状态,从而保证事务要么全部成功,要么全部失败。
持久性
MySQL 的持久性主要由预写 Redo Log、双写机制、两阶段提交以及 Checkpoint 刷盘机制共同保证。
当事务提交时,MySQL 会先将事务的修改操作写入 Redo Log,并强制刷盘,然后再将内存中的数据页刷入磁盘。这样即使系统崩溃,重启后也能通过 Redo Log 重放恢复数据。
隔离性
主要通过锁机制和 MVCC 来实现。
比如说一个事务正在修改某条数据时,MySQL 会通过临键锁来防止其他事务同时进行修改,避免数据冲突
MySQL默认事务自动提交
事务的隔离级别
MySQL 支持四种隔离级别,分别是:读未提交、读已提交、可重复读和串行化。
读未提交
事务可以读取其他未提交事务修改的数据。也就是说,如果未提交的事务一旦回滚,读取到的数据就会变成了“脏数据”,通常不会使用。
读已提交
读已提交避免了脏读,但可能会出现不可重复读,即同一事务内多次读取同一数据结果会不同,因为其他事务提交的修改,对当前事务是可见的。
可重复读
可重复读能确保同一事务内多次读取相同数据的结果一致,即使其他事务已提交修改。
串行化
串行化是最高的隔离级别,通过强制事务串行执行来解决“幻读”问题。
事务的隔离级别如何实现
读未提交通过行锁共享锁确保一个事务在更新行数据但没有提交的情况下,其他事务不能更新该行数据,但不会阻止脏读,意味着事务2 可以在事务1 提交之前读取到事务1 修改的数据
读已提交会在更新数据前加行级排他锁,不允许其他事务写入或者读取未提交的数据,也就意味着事务2 不能在事务 1 提交之前读取到事务1 修改的数据,从而解决脏读的问题。
可重复读只在第一次读操作时生成 ReadView,后续读操作都会使用这个 ReadView,从而避免不可重复读的问题。
另外,对于当前读操作,可重复读会通过临键锁来锁住当前行和前间隙,防止其他事务在这个范围内插入数据,从而避免幻读的问题。
MVCC
多版本并发控制
每次修改数据时,都会生成一个新的版本,而不是直接在原有数据上进行修改。并且每个事务只能看到在它开始之前已经提交的数据版本。
其底层实现主要依赖于 Undo Log 和 Read View。
版本链
版本链是指 InnoDB 中同一条记录的多个历史版本,通过 DB_ROLL_PTR 字段将它们像链表一样串起来,用来支持 MVCC 的快照读。
READVIEW
ReadView 是 InnoDB 为每个事务创建的一份“可见性视图”,用于判断在执行快照读时,哪些数据版本是当前这个事务可以看到的,哪些不能看到。
高可用
MySQL数据库的读写分离
读写分离就是把“写操作”交给主库处理,“读操作”分给多个从库处理,从而提升系统并发性能。
应用层通过中间件(如 MyCat、ShardingSphere)自动路由请求,将 INSERT / UPDATE / DELETE 等写操作发送给主库,将 SELECT 查询操作发送给从库。
主从复制
MySQL 的主从复制是一种数据同步机制,用于将数据从主数据库复制到一个或多个从数据库。
主库执行事务提交时,将数据变更以事件形式记录到 Binlog。从库通过 I/O 线程从主库的 Binlog 中读取变更事件,并将这些事件写入到本地的中继日志文件中,SQL 线程会实时监控中继日志的内容,按顺序读取并执行这些事件,从而保证从库与主库数据一致。
主从同步延迟怎么处理
主从同步延迟是因为从库需要先接收 binlog,再执行 SQL 才能同步主库数据,在高并发写或网络抖动时容易出现延迟,导致读写不一致。
第一种解决方案:对一致性要求高的查询(如支付结果查询)可以直接走主库。
第二种解决方案:对于非关键业务允许短暂数据不一致,可以提示用户“数据同步中,请稍后刷新”,然后借助异步通知机制替代实时查询。
第三种解决方案:采用半同步复制,主库在事务提交时,要等至少一个从库确认收到 binlog(但不要求执行完成),才算提交成功。
分库策略
分库的策略有两种,第一种是垂直分库:按照业务模块将不同的表拆分到不同的库中,比如说用户、登录、权限等表放在用户库中,商品、分类、库存放在商品库中,优惠券、满减、秒杀放在活动库中。
第二种是水平分库:按照一定的策略将一个表中的数据拆分到多个库中,比如哈希分片和范围分片,对用户 id 进行取模运算或者范围划分,将数据分散到不同的库中。
水平分库分表的策略
常见的分片策略有三种,范围分片、Hash 分片和路由分片。
范围分片是根据某个字段的值范围进行水平拆分。适用于分片键具有连续性的场景
Hash 分片是指通过对分片键的值进行哈希取模,将数据均匀分布到多个库表中,适用于分片键具有离散性的场景。
路由分片是通过路由配置来确定数据应该存储在哪个库表,适用于分片键不规律的场景。