如何通过MySql实践关系型数据库应用开发?
摘要:多年开发实践中遇到的DB相关的话题研究和整理,不介绍DB的基本概念,也不过于深入DB原理,以满足日常应用、知其然知其所以然为准。
包含十几个子话题,含事务传播性、索引优化、拆分、FailOver等。
本文主要是对目前工作中使用到的DB相关知识点的总结,应用开发了解到以下深度基本足以应对日常需求,再深入下去更偏向于DB本身的理论、调优和运维实践。
不在本文重点关注讨论的内容(可能会提到一些):
具体的DQL、DML、DDL、DCL等语法
基础性的概念,如主键、索引、存储过程(即sql级的编程。注:阿里巴巴规范中禁止使用存储过程)等
联合查询,我个人不太喜欢在应用中写过于复杂的SQLsu,性能和后续维护容易出现问题
可能会用到的具体DB特性,如oracle的DATA GUARD
有一些属于基础知识或语法但是常用的信息,也会列一下,如join的用法。
一、基础
1.1 ACID
DB的四大特性。 (错)
衡量事务的四个维度 (对)
原子性(Atomicity):事务操作中的多条SQL,要么全部成功要么全部失败,失败后回滚不对原有数据造成任何影响。
一致性(Consistency):事务开始前和结束后,数据库的完整性没有被破坏。如触发器、约束、级联回滚
隔离性(Isolation):多个事务支持并发读写。具体隔离级别见后文。
持久性(Durability):事务结束后,修改是永久的,不丢失。
如MySql:
原子性通过undo log保证
隔离性通过锁、MVCC近似保证
持久性通过undo/redo log和binlog保证
一致性通过以上三方面及应用层面保证
1.2 范式
这里展开讲比较复杂,实践中很少用到,一般满足1NF即可。
高一级必满足低一级。
1NF:每个属性都不可再分,即表的列是最原子的
2NF:在1NF基础上,消除非主属性对键的部分依赖。这里不解释非主属性和键的含义,可以简单认为是指不存在列A可以通过列B来获取,如“学生姓名-学号”这种y=f(x)的函数关系。
3NF:在2NF的基础之上,消除了非主属性对于码的传递函数依赖
BCNF:对于关系模式R,如果每一个函数依赖的决定因素都包含键,则R属于BCNF范式
有兴趣可以参考:范式通俗理解:1NF、2NF、3NF和BNCF
二、事务
事务的隔离级别
读现象
读现象是伴生于不同的隔离级别出现的。读现象的场景都是在多个事务并发执行的前提下可能出现的:
脏读 —— 一个事务读取了另一个未提交事务执行过程中的数据。此时另一个事务可能会由于提交失败而回滚。
不可重复读 —— 一个事务执行过程中多次查询同一条数据但返回了不同查询结果。这说明在事务执行过程中,数据被其他事务修改并提交了。
幻读 —— 事务1先行查询了某种数据,在修改或插入提交之前,事务2对此类数据进行了插入或删除并提交,导致了事务1对预期结果的数量变化。
隔离级别
未提交读(read uncommited):允许另外一个事务可以看到这个事务未提交的数据。
提交读(read commited):保证一个事务提交后才能被另外一个事务读取,而不能读取未提交的数据。
可重复读(repeatable read):保持读锁和写锁一直到事务提交,但不提供范围锁,因此不能避免幻读。
可序列化(serializable):代价最高但最可靠的事务隔离级别,事务被处理为顺序执行。
隔离级别与读现象
不同的隔离级别可以防止读现象。
隔离级别 脏读 不可重复读 幻影读
未提交读 可能发生 可能发生 可能发生
提交读 - 可能发生 可能发生
可重复读 - - 可能发生
可序列化 - - -
注:为什么提交读不能避免不可重复读?假设A事务需要读取两次变量a,第一次读取时a=10,执行过程中a被事务B修改变成了20,那么A第二次读时a与第一次的结果不同。
查看DB的隔离级别
// 查看当前会话
select @@tx_isolation;
// 查看当前系统
select @@global.tx_isolation;
MySql 5.7.14-ALISQL版默认是提交读。
2.2 事务传播性(Spring)
在多个含有事务方法的相互调用时,事务如何在这些方法间传播。
本节使用Spring事务注解的枚举,而不是全称(如PROPAGATION_REQUIRED)。
这里只支持单个库的事务。跨库事务请参考分布式事务章节。
spring支持7种事务传播行为:
REQUIRED:如果当前没有事务,就新建一个事务;否则加入到这个已有事务中,这是最常见的选择。
SUPPORTS:支持当前事务,如果没有当前事务,就以非事务方法执行。
MANDATORY:使用当前事务,如果没有当前事务,就抛出异常。
REQUIRED_NEW:新建事务,如果当前存在事务,把当前事务挂起。
