• MySQL(五)事务和三大范式


      MySQL是一个关系型数据库管理系统。

    一、SQL语句分类

    • 数据定义语言DDL:create,drop,alter主要为这几个操作,即对逻辑结构等有操作的,其中包括表结构、视图和索引。
    • 数据查询语言DQL:select,即查询操作,以select关键字,各种简单查询、连接查询都属于DQL。
    • 数据操纵语言DML:insert,update,delete主要为这几个操作,即对数据进行操作的,
    • 数据控制功能DCL:grant,revoke,commit,rollback主要为这几个操作,即对数据库安全性、完整性等有操作的,可以理解为权限控制。

    二、MySQL事务

      MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

    四个特性,ACID:

    • A(原子性Atomicity):原子性指的是事务是一个不可分割的,要么都执行要么都不执行
    • C(一致性Consistency):事务必须使得数据库从一个一致性状态,到另一个一致性状态
    • I(隔离性Isolation):指的是一个事务的执行,不能被其他的事务所干扰
    • D(持久性Durability):持久性指的是一个事务一旦提交了之后,对数据库的改变就是永久的

    并发事务处理带来的问题

      更新丢失(Lost Update):事务A和事务B选择同一行,然后基于最初选定的值更新该行时,由于两个事务都不知道彼此的存在,就会发生丢失更新问题。

      脏读(Dirty Reads):事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。

      不可重复读(Non-Repeatable Reads):事务 A 多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。

      幻读(Phantom Reads):幻读与不可重复读类似。它发生在一个事务A读取了几行数据,接着另一个并发事务B插入了一些数据时。在随后的查询中,事务A就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

    幻读和不可重复读的区别:

    • 不可重复读的重点是修改:在同一事务中,同样的条件,第一次读的数据和第二次读的数据不一样。(因为中间有其他事务提交了修改)
    • 幻读的重点在于新增或者删除:在同一事务中,同样的条件,,第一次和第二次读出来的记录数不一样。(因为中间有其他事务提交了插入/删除)

    创建一个事务

      事务可以划分为两大类,显示事务和隐式事务。隐式的事务很简单,比如insert、delete、update和select;显示事务就是很明显的开始和结束标记。接着来创建一个显示事务。

    1. 禁用步骤提交功能 set autocommit = 0
    2. 开启一个事务 start transaction
    3. SQL语句:update table user set money=500 where name = "张三";update table user set money=1500 where name = "李四";
    4. 结束事务,commit或者rollback。

    并发事务处理带来的问题解决办法

      “更新丢失”通常是应该完全避免的。但防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决,因此,防止更新丢失应该是应用的责任。

      “脏读” 、 “不可重复读”和“幻读” ,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决:一种是加锁:在读取数据前,对其加锁,阻止其他事务对数据进行修改。

      另一种是数据多版本并发控制(MultiVersion Concurrency Control,简称 MVCC 或 MCC),也称为多版本数据库:不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本。

    事务的隔离级别

    事务隔离级别 脏读 不可重复读 幻读                          
    读未提交(read-uncommitted) 三种现象都可能发生
    不可重复读(read-committed) 只允许读取已提交的数据
    可重复读(repeatable-read) 读取期间,其他事务不能更新

     

     

    • 未提交读(Read Uncommitted):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

    • 提交读(Read Committed):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
    • 可重复读(Repeated Read):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
    • SERIALIZABLE(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

    查看当前数据库的事务隔离级别:show variables like 'tx_isolation'

    小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

      数据库的事务隔离越严格,并发副作用越小,但付出的代价就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。

    Read uncommitted:读未提交,就是一个事务可以读取另一个未提交事务的数据。

    事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。
    分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。

    Read committed:读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

    事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…
    分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。那怎么解决可能的不可重复读问题?Repeatable read !
    Repeatable read:重复读,就是在开始读取数据(事务开启)时,不再允许修改操作。MySQL的默认事务隔离级别
    事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。
    分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。
    什么时候会出现幻读?
    事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。
    那怎么解决幻读问题?Serializable!
    Serializable 序列化
    Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。简单来说,Serializable会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用问题。这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

      事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个地方没有万能的原则。MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。

      这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 REPEATABLE-READ(可重读)事务隔离级别下使用的是Next-Key Lock 算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)已经可以完全保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串行化)隔离级别,而且保留了比较好的并发性能。

    三、MySQL三大范式

    第一范式

    1NF,强调的是列的原子性,也就是列不能再被分割。如电话列可进行拆分---家庭电话、公司电话

    第二范式

    2NF,首先是 1NF,另外包含两部分内容,一是表必须有主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。例如:订单表(订单编号、产品编号、定购日期、价格、……),"订单编号"为主键,"产品编号"和主键列没有直接的关系,即"产品编号"列不依赖于主键列,应删除该列。

    第三范式

    3NF,首先是 2NF,目标是确保每列都和主键列直接相关,而不是间接相关(另外非主键列必须直接依赖于主键,不能存在传递依赖).

    为了理解第三范式,需要根据Armstrong公里之一定义传递依赖。假设A、B和C是关系R的三个属性,如果A-〉B且B-〉C,则从这些函数依赖中,可以得出A-〉C,如上所述,
    依赖A-〉C是传递依赖。
    例如:订单表(订单编号,定购日期,顾客编号,顾客姓名,……),初看该表没有问题,满足第二范式,每列都和主键列"订单编号"相关,再细看你会发现"顾客姓名"和"顾客
    编号"相关,"顾客编号"和"订单编号"又相关,最后经过传递依赖,"顾客姓名"也和"订单编号"相关。为了满足第三范式,应去掉"顾客姓名"列,放入客户表中。

      

  • 相关阅读:
    写接口注意事项
    django-redis缓存
    ubuntu 16.04 ssh免密码连接不上
    ubuntu 16.04 配置静态ip 后默认的网卡eno1变成eth0了不能联网的问题解决
    ubuntu 16.04在真实机安装后的静态ip的配置
    ubuntu 16.04 静态ip的配置
    大数据Web可视化分析系统开发
    Structrued Streaming业务数据实时分析
    Spark Streaming实时数据分析
    Spark SQL快速离线数据分析
  • 原文地址:https://www.cnblogs.com/yfstudy/p/13549721.html
Copyright © 2020-2023  润新知