什么网站上可以做国际贸易跑流量的网站
什么网站上可以做国际贸易,跑流量的网站,公司简介图片,做长海报的网站文章目录一、基础概念1.1 逻辑架构和存储引擎1.2 提交和回滚1.3 ACID特性二、原子性2.1 定义2.2 实现原理#xff1a;undo log三、持久性3.1 定义3.2 实现原理#xff1a;redo log3.3 redo log与binlog3.3为什么有了binlog还要有redo log#xff1f;3.4 什么是两阶段提交……#一条或多条sql语句commit;其中start transaction标识事务开始commit提交事务将执行结果写入到数据库。如果sql语句执行出现问题会调用rollback回滚所有已经执行成功的sql语句。当然也可以在事务中直接使用rollback语句进行回滚。自动提交MySQL中默认采用的是自动提交autocommit模式如下所示在自动提交模式下如果没有start transaction显式地开始一个事务(start transaction会隐式地关闭自动提交)那么每个sql语句都会被当做一个事务执行提交操作。通过如下方式可以关闭autocommit需要注意的是autocommit参数是针对连接的在一个连接中修改了参数不会对其他连接产生影响。如果关闭了autocommit则所有的sql语句都在一个事务中直到执行了commit或rollback该事务结束同时开始了另外一个事务。特殊操作在MySQL中存在一些特殊的命令如果在事务中执行了这些命令会马上强制执行commit提交事务如DDL语句(create table/drop table/alter/table)、lock tables语句等等。不过常用的select、insert、update和delete命令都不会强制提交事务。1.3 ACID特性ACID是衡量事务的四个特性原子性Atomicity或称不可分割性: 事务中的操作要么全都成功要么全都失败如果出现一些成功一些失败事务将会回滚到事务开始前的状态。一致性Consistency: 事务的一致性保证了事务完成后数据库能够处于一致性状态。隔离性Isolation: 同一时刻执行多个事务时一个事务的执行不能被其他事务干扰。持久性Durability: 持久性意味着事务一旦成功执行在系统中产生的所有变化将是永久的。按照严格的标准只有同时满足ACID特性才是事务但是在各大数据库厂商的实现中真正满足ACID的事务少之又少。例如MySQL的NDB Cluster事务不满足持久性和隔离性InnoDB默认事务隔离级别是可重复读不满足隔离性Oracle默认的事务隔离级别为READ COMMITTED不满足隔离性……因此与其说ACID是事务必须满足的条件不如说它们是衡量事务的四个维度。下面将详细介绍ACID特性及其实现原理为了便于理解介绍的顺序不是严格按照A-C-I-D。二、原子性2.1 定义原子性是指一个事务是一个不可分割的工作单位其中的操作要么都做要么都不做如果事务中一个sql语句执行失败则已执行的语句也必须回滚数据库退回到事务前的状态。2.2 实现原理undo log在说明原子性原理之前首先介绍一下MySQL的事务日志。MySQL的日志有很多种如二进制日志、错误日志、查询日志、慢查询日志等此外InnoDB存储引擎还提供了两种事务日志redo log(重做日志)和undo log(回滚日志)。其中redo log用于保证事务持久性undo log则是事务原子性和隔离性实现的基础。日志部分可参考mysql中的7种日志。redo log通常是物理日志记录的是数据页的物理修改而不是某一行或某几行修改成怎样怎样它用来恢复提交后的物理数据页(恢复数据页且只能恢复到最后一次提交的位置)。undo log用来回滚行记录到某个版本。undo log一般是逻辑日志根据每行记录进行记录。实现原子性的关键是当事务回滚时能够撤销所有已经成功执行的sql语句。InnoDB实现回滚靠的是undo log当事务对数据库进行修改时InnoDB会生成对应的undo log如果事务执行失败或调用了rollback导致事务需要回滚便可以利用undo log中的信息将数据回滚到修改之前的样子。undo log属于逻辑日志它记录的是sql执行相关的信息。当发生回滚时InnoDB会根据undo log的内容做与之前相反的工作对于每个insert回滚时会执行delete对于每个delete回滚时会执行insert对于每个update回滚时会执行一个相反的update把数据改回去。当delete一条数据的时候就需要记录这条数据的信息回滚的时候insert这条旧数据。当update一条数据的时候就需要记录之前的旧值回滚的时候根据旧值执行update操作。当insert一条数据的时候就需要这条记录的主键回滚的时候根据主键执行delete操操作。以update操作为例当事务执行update时其生成的undo log中会包含被修改行的主键(以便知道修改了哪些行)、修改了哪些列、这些列在修改前后的值等信息回滚时便可以使用这些信息将数据还原到update之前的状态。三、持久性3.1 定义持久性是指事务一旦提交它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。3.2 实现原理redo logredo log和undo log都属于InnoDB的事务日志。下面先聊一下redo log存在的背景。InnoDB作为MySQL的存储引擎数据是存放在磁盘中的但如果每次读写数据都需要磁盘IO效率会很低。为此InnoDB提供了缓存(Buffer Pool)Buffer Pool中包含了磁盘中部分数据页的映射作为访问数据库的缓冲当从数据库读取数据时会首先从Buffer Pool中读取如果Buffer Pool中没有则从磁盘读取后放入Buffer Pool当向数据库写入数据时会首先写入Buffer PoolBuffer Pool中修改的数据会定期刷新到磁盘中这一过程称为刷脏。Buffer Pool的使用大大提高了读写数据的效率但是也带了新的问题如果MySQL宕机而此时Buffer Pool中修改的数据还没有刷新到磁盘就会导致数据的丢失事务的持久性无法保证。于是redo log被引入来解决这个问题当数据修改时除了修改Buffer Pool中的数据还会在redo log记录这次操作当事务提交时会调用fsync接口对redo log进行刷盘。如果MySQL宕机重启时可以读取redo log中的数据对数据库进行恢复。redo log采用的是WALWrite-ahead logging预写式日志所有修改先写入日志再更新到Buffer Pool保证了数据不会因MySQL宕机而丢失从而满足了持久性要求。MySQL支持用户自定义在commit时如何将log buffer中的日志刷log file中。这种控制通过变量innodb_flush_log_at_trx_commit的值来决定。该变量有3种值0、1、2默认为1。但注意这个变量只是控制commit动作是否刷新log buffer到磁盘。当设置为1的时候事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据但是因为每次提交都写入磁盘IO的性能较差。当设置为0的时候事务提交时不会将log buffer中日志写入到os buffer而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的当系统崩溃会丢失1秒钟的数据。当设置为2的时候每次提交都仅写入到os buffer然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。既然redo log也需要在事务提交时将日志写入磁盘为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢主要有以下两方面的原因刷脏是随机IO因为每次修改的数据位置随机但写redo log是追加操作属于顺序IO。刷脏是以数据页Page为单位的MySQL默认页大小是16KB一个Page上一个小修改都要整页写入而redo log中只包含真正需要写入的部分无效IO大大减少。没有redo log直接刷脏修改数据内存→ COMMIT → 定位磁盘上的脏页位置随机寻道→ 写入整页数据16KB→ 事务完成有redo log先写 redo 再异步刷脏:BEGIN → 修改数据内存→ 生成 Redo Log内存 Buffer→ COMMIT → 追加写入 Redo Log 到磁盘顺序写 小日志→ 事务完成 后台异步→ 空闲时刷脏页到磁盘随机写 整页写入整体就是没有 redo log每一次事务提交都要触发一次随机写IO 请求密集且低效有 redo log事务提交的高频 IO 变成了顺序写Redo Log而随机写刷脏只在系统空闲时批量执行减少了磁盘寻道的次数整体 IO 效率提升。关于redo log和undo log区别参看详细分析MySQL事务日志(redo log和undo log)3.3 redo log与binlog我们知道在MySQL中还存在binlog(二进制日志)也可以记录写操作并用于数据的恢复但二者是有着根本的不同的1作用不同redo log是用于crash recovery的保证MySQL宕机也不会影响持久性binlog是用于point-in-time recovery的保证服务器可以基于时间点恢复数据此外binlog还用于主从复制。2层次不同redo log是InnoDB存储引擎实现的而binlog是MySQL的服务器层实现的同时支持InnoDB和其他存储引擎。3内容不同redo log是物理日志内容基于磁盘的Pagebinlog的内容是二进制的根据binlog_format参数的不同可能基于sql语句、基于数据本身或者二者的混合。4写入时机不同binlog在事务提交时写入redo log的写入时机相对多元前面曾提到当事务提交时会调用fsync对redo log进行刷盘这是默认情况下的策略修改innodb_flush_log_at_trx_commit参数可以改变该策略但事务的持久性将无法保证。除了事务提交时还有其他刷盘时机如master thread每秒刷盘一次redo log等这样的好处是不一定要等到commit时刷盘commit速度大大加快。3.3为什么有了binlog还要有redo logbinlog会记录所有与MySQL数据库有关的日志记录包括InnoDB, MyISAMHeap等其他存储引起的日志。而redo log只记录innodb引擎本身的日志。binlog记录的是关于一个事务的具体操作内容即该日志是逻辑日志。而redolog记录的是关于每个页的更改的物理情况。写入时间不同。binlog仅在事务提交前提交只写磁盘一次不论这个事务有多大。而redolog在事务进行过程中会不停的写入。它们分工是不同的。binlog用来做数据归档但不具备崩溃恢复的能力也就是说如果系统突然崩溃重启后可能会有部分数据丢失。innodb将所有对页面的修改操作写入一个专门的文件并在数据库启动时从此文件进行恢复操作。详细地参考为什么有binlog还要redo log3.4 什么是两阶段提交所谓的两阶段就是把一个事物分成两个阶段来提交。就像下图这样执行流程1、执行器先从引擎中找到数据如果在内存中直接返回如果不在内存中查询后返回。2、执行器拿到数据之后会先修改数据然后调用引擎接口重新写入数据。3、引擎将数据更新到内存同时写数据到redo中此时处于prepare阶段并通知执行器执行完成随时可以操作。4、执行器生成这个操作的binlog。5、执行器调用引擎的事务提交接口引擎把刚刚写完的redo改成commit状态更新完成。3.5 为什么需要两阶段提交?因为MySQL有两个日志文件我们需要两个日志都写入我们需要保证两个日志的一致性。那么如果不使用两阶段提交的方式直接写入redo log然后写入binlog有什么问题呢先写redo log后写binlog: 假设在redo log写完c字段为1binlog还没有写完的时候MySQL进程异常重启。由于我们前面说过的redo log写完之后系统即使崩溃仍然能够把数据恢复回来所以恢复后这一行c的值是1。但是由于binlog没写完就crash了这时候binlog里面就没有记录这个语句。因此之后备份日志的时候存起来的binlog里面就没有这条语句。然后你会发现如果需要用这个binlog来恢复临时库的话由于这个语句的binlog丢失这个临时库就会少了这一次更新恢复出来的这一行c的值就是0与原库的值不同。先写binlog后写redo log: 如果在binlog写完之后crash由于redo log还没写崩溃恢复以后这个事务无效所以这一行c的值是0。但是binlog里面已经记录了“把c从0改成1”这个日志。所以在之后用binlog来恢复的时候就多了一个事务出来恢复出来的这一行c的值就是1与原库的值不同。所以需要两阶段提交来保证数据一致性。如果这时候写完redo log后挂掉了因为redo log和binlog都没有数据所以会回滚事务。 如果binlog和redo log都写入了但是没有提交那么重启后会提交事务。这样binlog和数据库就都有数据了。四、隔离性4.1 定义与原子性、持久性侧重于研究事务本身不同隔离性研究的是不同事务之间的相互影响。隔离性是指事务内部的操作与其他事务是隔离的并发执行的各个事务之间不能互相干扰。严格的隔离性对应了事务隔离级别中的Serializable (可串行化)但实际应用中出于性能方面的考虑很少会使用可串行化。隔离性追求的是并发情形下事务之间互不干扰。简单起见我们主要考虑最简单的读操作和写操作(加锁读等特殊读操作会特殊说明)那么隔离性的探讨主要可以分为两个方面(一个事务)写操作对(另一个事务)写操作的影响锁机制保证隔离性(一个事务)写操作对(另一个事务)读操作的影响MVCC保证隔离性4.2 锁机制首先来看两个事务的写操作之间的相互影响。隔离性要求同一时刻只能有一个事务对数据进行写操作InnoDB通过锁机制来保证这一点。锁机制的基本原理可以概括为事务在修改数据之前需要先获得相应的锁获得锁之后事务便可以修改数据该事务操作期间这部分数据是锁定的其他事务如果需要修改数据需要等待当前事务提交或回滚后释放锁。行锁与表锁按照粒度锁可以分为表锁、行锁以及其他位于二者之间的锁。表锁在操作数据时会锁定整张表并发性能较差行锁则只锁定需要操作的数据并发性能好。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源)因此在锁定数据较多情况下使用表锁可以节省大量资源。MySQL中不同的存储引擎支持的锁是不一样的例如MyIsam只支持表锁而InnoDB同时支持表锁和行锁且出于性能考虑绝大多数情况下使用的都是行锁。如何查看锁信息有多种方法可以查看InnoDB中锁的情况例如select*frominformation_schema.innodb_locks;#锁的概况showengineinnodbstatus;#InnoDB整体状态其中包括锁的情况下面来看一个例子show engine innodb status查看锁相关的部分通过上述命令可以查看事务24052和24053占用锁的情况其中lock_type为RECORD代表锁为行锁(记录锁)lock_mode为X代表排它锁(写锁)。除了排它锁(写锁)之外MySQL中还有共享锁(读锁)的概念。由于本文重点是MySQL事务的实现原理因此对锁的介绍到此为止。可参见MySQL 表锁、行锁、间隙锁、页锁介绍分析和详解 MySql InnoDB 中意向锁的作用介绍完写操作之间的相互影响下面讨论写操作对读操作的影响。4.3 脏读、不可重复读和幻读首先来看并发情况下读操作可能存在的三类问题1脏读当前事务(A)中可以读到其他事务(B)未提交的数据脏数据这种现象是脏读。举例如下以账户余额表为例2不可重复读在事务A中先后两次读取同一个数据两次读取的结果不一样这种现象称为不可重复读。脏读与不可重复读的区别在于前者读到的是其他事务未提交的数据后者读到的是其他事务已提交的数据。举例如下3幻读在事务A中按照某个条件先后两次查询数据库两次查询结果的条数不同这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为前者是数据变了后者是数据的行数变了。举例如下4.4 事务隔离级别SQL标准中定义了四种隔离级别并规定了每种隔离级别下上述几个问题是否存在。一般来说隔离级别越低系统开销越低可支持的并发越高但隔离性也越差。隔离级别与读问题的关系如下在实际应用中读未提交在并发时会导致很多问题而性能相对于其他隔离级别提高却很有限因此使用较少。可串行化强制事务串行并发效率很低只有当对数据一致性要求极高且可以接受没有并发时使用因此使用也较少。因此在大多数数据库系统中默认的隔离级别是读已提交(如Oracle)或可重复读后文简称RR。可以通过如下两个命令分别查看全局隔离级别和本次会话的隔离级别InnoDB默认的隔离级别是RR后文会重点介绍RR。需要注意的是在SQL标准中RR是无法避免幻读问题的但是InnoDB实现的RR隔离级别在一定程度上避免了幻读问题。5.5 MVCCRR解决脏读、不可重复读、幻读等问题使用的是MVCCMVCC全称Multi-Version Concurrency Control即多版本的并发控制协议。下面的例子很好的体现了MVCC的特点在同一时刻不同的事务读取到的数据可能是不同的(即多版本)——在T5时刻事务A和事务C可以读取到不同版本的数据。MVVC详细可参考MVCC多版本并发控制MVCC最大的优点是读不加锁因此读写不冲突并发性能好。InnoDB实现MVCC多个版本的数据可以共存主要基于以下技术及数据结构1隐藏列InnoDB中每行数据都有隐藏列隐藏列中包含了本行数据的事务id、指向undo log的指针等。2基于undo log的版本链前面说到每行数据的隐藏列中包含了指向undo log的指针而每条undo log也会指向更早版本的undo log从而形成一条版本链。3ReadView通过隐藏列和版本链MySQL可以将数据恢复到指定版本但是具体要恢复到哪个版本则需要根据ReadView来确定。所谓ReadView是指事务记做事务A在某一时刻给整个事务系统trx_sys打快照之后再进行读操作时会将读取到的数据中的事务id与trx_sys快照比较从而判断数据对该ReadView是否可见即对事务A是否可见。Read View说白了Read View就是事务进行快照读操作的时候产生的读视图(Read View)在该事务执行的快照读的那一刻会生成数据库系统当前的一个快照记录并维护系统当前活跃事务的ID(当每个事务开启时都会被分配一个ID, 这个ID是递增的所以最新的事务ID值越大)。所以我们知道 Read View主要是用来做可见性判断的, 即当我们某个事务执行快照读的时候对该记录创建一个Read View读视图把它比作条件用来判断当前事务能够看到哪个版本的数据既可能是当前最新的数据也有可能是该行记录的undo log里面的某个版本的数据。trx_sys中的主要内容以及判断可见性的方法如下low_limit_id表示生成ReadView时系统中应该分配给下一个事务的id。如果数据的事务id大于等于low_limit_id则对该ReadView不可见。up_limit_id表示生成ReadView时当前系统中活跃的读写事务中最小的事务id。如果数据的事务id小于up_limit_id则对该ReadView可见。rw_trx_ids表示生成ReadView时当前系统中活跃的读写事务的事务id列表。如果数据的事务id在low_limit_id和up_limit_id之间则需要判断事务id是否在rw_trx_ids中如果在说明生成ReadView时事务仍在活跃中因此数据对ReadView不可见如果不在说明生成ReadView时事务已经提交了因此数据对ReadView可见。下面以RR隔离级别为例结合前文提到的几个问题分别说明。1脏读当事务A在T3时刻读取zhangsan的余额前会生成ReadView由于此时事务B没有提交仍然活跃因此其事务id一定在ReadView的rw_trx_ids中因此根据前面介绍的规则事务B的修改对ReadView不可见。接下来事务A根据指针指向的undo log查询上一版本的数据得到zhangsan的余额为100。这样事务A就避免了脏读。2不可重复读当事务A在T2时刻读取zhangsan的余额前会生成ReadView。此时事务B分两种情况讨论一种是如图中所示事务已经开始但没有提交此时其事务id在ReadView的rw_trx_ids中一种是事务B还没有开始此时其事务id大于等于ReadView的low_limit_id。无论是哪种情况根据前面介绍的规则事务B的修改对ReadView都不可见。当事务A在T5时刻再次读取zhangsan的余额时会根据T2时刻生成的ReadView对数据的可见性进行判断从而判断出事务B的修改不可见因此事务A根据指针指向的undo log查询上一版本的数据得到zhangsan的余额为100从而避免了不可重复读。3幻读MVCC避免幻读的机制与避免不可重复读非常类似。当事务A在T2时刻读取0id5的用户余额前会生成ReadView。此时事务B分两种情况讨论一种是如图中所示事务已经开始但没有提交此时其事务id在ReadView的rw_trx_ids中一种是事务B还没有开始此时其事务id大于等于ReadView的low_limit_id。无论是哪种情况根据前面介绍的规则事务B的修改对ReadView都不可见。当事务A在T5时刻再次读取0id5的用户余额时会根据T2时刻生成的ReadView对数据的可见性进行判断从而判断出事务B的修改不可见。因此对于新插入的数据lisi(id2)事务A根据其指针指向的undo log查询上一版本的数据发现该数据并不存在从而避免了幻读。这里要解释一下MySQL标准情况下在 RR(Repeatable Read) 隔离级别下能解决不可重复读当行修改的问题但是不能解决幻读的问题。在InnoDB的RR隔离级别下是能解决部分幻读问题的但不能完全阻止这是怎么实现的呢InnoDB引擎RR隔离级别下并不能完全阻止幻读的发生想避免幻读要保证gap锁是开启的也就是innodb_locks_unsafe_for_binlog参数值为off默认情况是off在这里要区分一下快照读和当前读:快照读就是普通的selectselect*fromtable当前读加了锁的增删改查读取的都是当前最新的数据select*fromtablewhere?lockinsharemode;select*fromtablewhere?forupdate;insert;update;delete;对于快照读的场景通过mvcc版本管理来解决幻读的问题。就是a事务只做了两次查询操作两次查询中间即使有符合条件的插入第二次查询的结果也是原来的数据信息。但是这仅仅是表象我们继续看内因。表象快照读通过MMVC基于事务版本控制的协议和undo日志实现的。内因Next-Key行锁和gap锁针对当前读的情况mysql是通过Next-Key锁搞定的。就是在当前读的情况下会加入一个范围锁锁住一个区间区间内如果有别的事务进行插入操作是要等待当前事务提交的。在where条件全部命中的情况下不加gap锁由于操作就在这个精确的范围内再新加入数据也不会影响这些数据那么不会发生幻读也不触发gap锁。在table表中精确查询id为135的数据假如全部都能查到不加gap锁select*fromtablewhereidin(1,3,5)在where条件没全部命中的情况下触发gap锁:在table表中精确查询id为135的数据只能部分查到1那么35会加gap锁插入id为3和id为5的值时要等事务1的查询结束提交才能插入select*fromtablewhereidin(1,3,5)gap锁的范围若 id的值为2691115那么范围为-∞2],(2,6],(6,9],(9,11],(11,15],(15,∞)由于锁的特性当某事务对数据进行加锁读后其他事务无法对数据进行写操作因此可以避免脏读和不可重复读。而避免幻读则需要通过next-key lock。next-key lock是行锁的一种实现相当于record lock(记录锁) gap lock(间隙锁)其特点是不仅会锁住记录本身(record lock的功能)还会锁定一个范围(gap lock的功能)。因此加锁读同样可以避免脏读、不可重复读和幻读保证隔离性。五、一致性5.1 基本概念一致性是指事务执行结束后数据库的完整性约束没有被破坏事务执行的前后都是合法的数据状态。数据库的完整性约束包括但不限于实体完整性如行的主键存在且唯一、列完整性如字段的类型、大小、长度要符合要求、外键约束、用户自定义完整性如转账前后两个账户余额的和应该不变。5.2 实现可以说一致性是事务追求的最终目标前面提到的原子性、持久性和隔离性都是为了保证数据库状态的一致性。此外除了数据库层面的保障一致性的实现也需要应用层面进行保障。实现一致性的措施包括保证原子性、持久性和隔离性如果这些特性无法保证事务的一致性也无法保证数据库本身提供保障例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等应用层面进行保障例如如果转账操作只扣除转账者的余额而没有增加接收者的余额无论数据库实现的多么完美也无法保证状态的一致。原文地址1、深入学习MySQL事务ACID特性的实现原理2、跟面试官侃半小时MySQL事务说完原子性、一致性、持久性的实现感兴趣的可以详读MySQL官方网站