mysql数据库工程师网易微专业_网易MySQL数据库工程师微专业学习笔记(五)

一、mysql数据库中的存储引擎

mysql在创建数据表时可以通过engine关键字设置存储引擎的类型,也可以通过alter命令来修改表的存储引擎。可以通过show engines命令来查看当前mysql数据库支持的存储引擎的类型,一般场景的存储引擎有:InnoDB、MyISAM、MEMORY、BLACKHOLE、TokuDB和MySQL Cluster。

InnoDB存储引擎是mysql5.5后的默认存储引擎,其特点主要有:1.索引组织表、2.支持事务、3.支持行级锁、4.数据块缓存、5.日志持久化。一般的线上项目推荐使用InnoDB存储引擎,因为其稳定可靠、性能好。

MyISAM存储引擎时mysql5.1之前的默认存储引擎,其特点主要有:1.堆表、2.不支持事务、3.只维护索引缓存块,表数据缓存交给操作系统、4.锁粒度大,表级锁,高并发下会有问题。5.数据文件可以直接拷贝。一般没有特殊需求不建议使用。

MEMORY存储引擎的特点有:1.数据全内存存放,无法持久化、2.性能较高、3.不支持事务。适合偶尔作为临时表的存储引擎使用。临时表创建是通过create temporary table来实现的,且临时表不是全局可见的,只用当前连接可见。

BLACKHOLE存储引擎的特点是:1.数据不做任何存储。一般利用mysql replicate充当日志服务器,再mysql replicate环境中充当代理主机。

TokuDB存储引擎的特点有:1.分形树存储结构、2.支持事务、3.行级锁、4.数据压缩效率高。一般使用于有大批量insert的业务场景,但是mysql官方版本中没有这个存储引擎,需要去其官网下载安装扩展。

MySQL Cluster存储引擎的特点有:1.多主机分布式集群、2.数据节点冗余、高可用、3.支持事物、4.设计易于扩展。这是一款面向未来发展的数据库,当前线上不建议使用。此外mysql官方版本中也没有这个存储引擎,需要去其官网下载安装扩展。

二、InnoDB事物锁

锁的作用是在并发的情况下保证数据的完整性和一致性。数据库中的锁有两种,1.事务锁lock,在事务的执行过程中保护数据库的逻辑内容。2.线程锁latch/mutex,多线程争夺临界资源时,保护内存数据结构。数据库中事务间用的是第一种事务锁来保护并发,将对同一行数据的修改串行化。

三、事务锁的粒度

1.行锁:InnoDB和Oracle中用的是行锁,即修改记录时只锁定这一行记录。

2.页所:SQL Server中用的是页锁,修改记录时锁定的是该记录所在的数据页。

3.表锁:MyISAM和MEMORY中用的是表锁,修改记录时锁定记录所在的表。

锁升级:当维护行锁或页锁的代价过高时,数据库会自动将锁升级为表锁,在InnoDB和Oracle中是不存在这种情况的,但是再SQL Server中有。

四、InnoDB中四种基本锁模式

InnoDB中有两种标准的行级锁,分别是共享锁(S Lock)和排它锁(X Lock)。共享锁就是读锁,允许事务读一行数据。排它锁就是写锁,允许事务删除或更新一行数据。量中锁的兼容性如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

此外InnoDB中还有一种被称为意向锁的锁,这种锁是由引擎自动添加和释放的,所以操作十分快,对用户而言可以认为是透明的。意向锁存在的目的是为数据库提供多粒度的上锁,例如当为一个行数据添加行锁时,先对数据所在的表和页添加表级和页级的意向锁,这样如果在表级或者页级就出现冲突,则不用在去检测行数据的锁兼容性了,可以减少冲突检测的代价,提高上锁的效率。一般行级锁是不会与意向锁冲突的。意向锁与读写锁的兼容性如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

五、InnoDB的加锁操作

一般的select语句不加任何的锁,也不会被任何事务锁阻塞,因为InnoDB中读操作采用的是一致性非锁定读,就是实际读取时不是读取的当前磁盘上的数据,而是这行数据的一个数据快照,可以认为就是一个回滚段。而多个版本的数据快照间的隔离性是由多版本并发控制(MVCC)来实现的。不同的事务级别下多版本并发控制也会有所不同,例如再READ COMMITTED级别下,总是会读取最新的一个数据快照,这样就会导致不可重复读。而在REPEATABLE READ级别下则是读取事务开始时的数据版本,这样就解决了不可重复读的问题。

S锁有两种上锁情况,一种是手动添加S锁,可以通过select * from table lock in share mode来手动添加S锁。另一种是自动添加,在执行insert操作前会自动添加S锁。

X锁也有两种上锁情况,一种是手动添加,可以通过select * from table lock for update。另一种是自动添加,在执行update和delete操作时会自动给这行数据添加X锁。

六、锁超时

当事务发现锁被其他事务获取后就进入等待,但是这个等待不是无休止的,InnoDB中有一个等待超时参数innodb_lock_wait_timeout,可以用show variables和set命令来查看和修改这个参数,该参数的单位是秒,一般默认设置是50秒,如果事务等待的时间超过了这个等待的上线时间就会抛出操作是吧的error。此外还有一个参数innodb_rollback_on__timeout用来设定是否在等待超时时对进行中的事务进行回滚操作(该参数值默认时OFF的,即关闭的),同样也可以用show variables和set命令来查看和修改这个参数。

七、InnoDB行锁的实现

InnoDB中的行锁是通过对索引项加锁实现的,而不是对一行数据的数据块进行加锁实现的(Oracle中是这样实现的)。因此只有当过滤条件走索引时才能实现行级锁,如果索引上有多条数据那就有可能同时锁住多条数据。而如果查询有多个索引可以使用时,可以对不同的索引加锁,这主要取决于mysql中的自动生成的执行计划。因此一般在做更新和删除条件时用自增主键来做条件性能最好。

下面通过具体实例来进行说明。

首先建立一张t2表并插入两条记录,sql语句如下。

create table t2(a int,b int,key idx1(a));

insert into t2 values(1,1);

insert into t2 values(1,5);

然后在连接A中开启事务,并执行如下命令。

mysql> select * from t2 where a=1 and b=5 for update;

接下来在连接B中开启事务执行如下命令。

select * from t2 where a=1 and b=1 for update;

执行结果如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

可以看出在执行连接A中的事务时虽然查询结果只有一行,但实际上是锁了两行记录,这就是因为InnoDB存储引擎中是使用锁索引的方法来实现行锁的。而上面的t2表中只有a列有索引,所以当执行连接A中的事务时存储引擎实际上是对a列值为1的数据都进行了锁定,所以锁了两行数据。而如果表中没有索引那么InnoDB就无法实现行锁了,每次锁定都将锁定表中的所有数据,就和表锁一样了。因此一般在update和delete操作中where条件中推荐使用自增主键来作为筛选条件,这样可以保证每次只锁定一行数据。

八、InnoDB的gap lock

InnoDB的gap lock是InnoDB中一种特殊的锁定算法,即锁定的时候不是单单锁定某个值下的索引记录,而是一个范围下的索引记录,其作用就是消灭幻读(什么是幻读可以去看上一篇博客)。但是其代价就是会降低数据库的并发性。下面来举例说明。

首先建立一张表t3并插入一些数据,代码如下。

create table t3(a int(11) default null,key idx1(a));

insert into t3 values(20),(23),(27),(27),(30),(31);

然后在连接A中开启事务,并执行如下命令。

select * from t3 where a=27 for update;

接下来在连接B中开启事务执行如下命令。

insert into t3 values(27);

结果如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

可以看出在连接B中27无法插入t3表中。这样就解决了幻读问题。看似很完美,但是之际上InnoDB中锁定的是(23,30)这样的数值范围,不知27无法插入了,连24、25、26、28、29都无法插入了。如果在B连接中执行如下语句。

insert into t3 values(28);

insert into t3 values(25);结果如下图。

0818b9ca8b590ca3270a3433284dd417.png

因此在gap lock下数据库的并发性是比较差的,因为每次都会锁掉一个范围内的数据。当然解决的方法也很简单,就是采用自增主键,update和delete的时候where条件中根据自增主键来定位数据,这样就能保证每次数据库只锁定一行数据。

九、死锁

死锁是指两个或两个以上的事务再执行过程中因争夺资源而造成的一种相互等待的现象。mysql中等待图的方式来检查是否存在死锁的情况,如果存在死锁则选择回滚代价最小的事务进行回滚。

虽然mysql中可以自动检测死锁,但是在实际开发中还是要尽量的避免死锁,否则并发效率会收到极大的影响。常用的预防死锁的方法有,1. 尽可能缩短事务的长度,单步事务是永远不会出现死锁的。2. 可能存在冲突的跨表事务尽量避免并发。3. 进行批量更新操作时尽量用自增主键来作为选择条件,并对主键值进行排序,这样就不会造成死锁了。举例来说,如果两个连接同时执行一下语句是不会有死锁的。

update tb_goods set store_quantity=store_quantity +10 where goods_id=1;

update tb_goods set store_quantity=store_quantity +10 where goods_id=3;

update tb_goods set store_quantity=store_quantity +10 where goods_id=7;

update tb_goods set store_quantity=store_quantity +10 where goods_id=9;因为where中用的是自增主键,且语句中的主键值是递增的,这样多个事务中是不会出现循环锁定的。

如果两个事务分别执行如下语句,则可能出现死锁。

事务A

update tb_goods set store_quantity=store_quantity +10 where goods_id=1;

update tb_goods set store_quantity=store_quantity +10 where goods_id=3;

update tb_goods set store_quantity=store_quantity +10 where goods_id=7;

update tb_goods set store_quantity=store_quantity +10 where goods_id=9;事务B

update tb_goods set store_quantity=store_quantity +10 where goods_id=3;

update tb_goods set store_quantity=store_quantity +10 where goods_id=1;

update tb_goods set store_quantity=store_quantity +10 where goods_id=7;

update tb_goods set store_quantity=store_quantity +10 where goods_id=9;当两个事务同事执行完第一个更新语句,主键值为1和3的行并锁定,接下来两个事务在分别请求

主键值为1和3的行就出现了循环等待,也就是死锁。

死锁存在的条件有三个,1.有两个以上的并发修改的事务;2. 多个事务都是多步的;3. 多步操作中想抢占的锁资源存在并发关系。只要破坏这三个条件中的任意一个,则死锁就可以避免。

当线上数据库出现大量死锁,就需要进行排查,排查时不止要检查死锁出现的sql语句,还有检查触发改sql语句的上下文以及具体的业务逻辑,根据上下文语句的加锁范围分析存在争用的记录,从而定位死锁出现的原因。

十、事务的组织

以简单的一个购物业务场景为例,流程图如下。

0818b9ca8b590ca3270a3433284dd417.png

简单来说就是用先想买商品1,那么先检查商品1是否有库存,如果有就将若干件商品1加入用户订单。接下来用户还想买商品2,那么再检查商品2是否有库存,如果有就将若干件商品2加入用户订单。最后用户确认提交订单并付款就完成了购物的操作。

这里需要用事务和锁来实现业务需求,原因有两个。

1. 因为业务需要保证操作的原子性,查询库存、更新订单和扣除库存要么都成功,要么都不成功,所以要用事务。

2. 要避免业务纠纷,业务中查询库存到扣除库存的过程中不能让库存再发生变化,因此要用锁,在查询库存的时候用for update人工加锁。

最简单的是用一个大事务来实现业务需求,如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

这样固然是可以保证业务的原子性的,确保库存不会被扣成负的。但是在实际业务中,往往用户在挑选完商品1后到用户再添加商品2这之间所间隔的时间是非常长的,这样会导致在很长的时间内只有一个人可以买商品1,这显然是不合理的。此外,如果用户挑选完商品1后连接意外中断了,当用户在重新连接回来后之前的未完成订单是找不到的,这肯定也是不能让人接受的。

因此需要对上面的大事务进行优化,将一个大事务切分为若干个小事务,例如上面的事物可以切分为三个小事务,一个是添加商品1的事务,一个是添加商品2的事务,最后是提交付款的事务,如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

如果是一个简单的购物网站,到这里就已经可以满足购物业务的需求了。但是像那行大的电商网站,这样还是不行的,因为可以每个商品下还有各种优惠、特价等,这样当将一个商品添加到订单中时不仅仅要检查是否有库存,还要检查是否有什么优惠、特价等等,这样事务就又变长了,商品锁定的时间又变长了,这对于大型电商网站是不能接受的,因此需要进一步优化。优化的方法也很简单,就是在用select检查库存时不用for update进行锁定了,而在执行update操作时添加一个判断条件,就是判断库存是否够,如下图所示。

0818b9ca8b590ca3270a3433284dd417.png

可能有人会疑问,既然这样,那为什么还要在update前进行select操作查询商品的库存,这么做主要有两个原因,首先,在用户下单前需要给用户展示还有多少商品。另外,这样可以事先判断是否有库存,如果没有就不用执行下面的update操作了,可以提升应用服务器和数据库服务器的性能。

总结来说,事物和锁的优化思路就是在保证业务正确的前提下,尽量缩短锁的时间。

十一、悬挂事务与锁超时排除

实际的线上维护时可能会出现几个记录被长时间的锁定,导致访问这些数据的请求全部超时,这有可能是有一些悬挂事务中锁定的数据。悬挂事务就是一些长时间没有提交且没有进行进一步操作的事务。悬挂事务出现的原因可能是用户连接突然中断,而应用服务器确保留了这个数据库连接和执行到一半的事务。

这样的情况用show processlist是无法定位有悬挂事务的连接的。show processlist只能查出当前有多少个连接,哪些是活跃的,哪些是不活跃的,但是无法找出哪些连接中有事务长时间的占着锁没有释放。

要查看悬挂事务的连接可以用如下语句来查询。

select trx_mysql_thread_id,trx_state,now()-trx_started,trx_rows_locked from information_schema.innodb_trx;查询的结果有四列,分别表示连接Id、当前状态、存在的时间、锁定的资源数。

找到悬挂事务后可以用kill命令来结束连接。但是因为无法知道阻塞的sql具体在执行什么,因此需要与业务确认看是否可以直接杀死连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368427.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java并发编程笔记之ConcurrentLinkedQueue源码探究

JDK 中基于链表的非阻塞无界队列 ConcurrentLinkedQueue 原理剖析,ConcurrentLinkedQueue 内部是如何使用 CAS 非阻塞算法来保证多线程下入队出队操作的线程安全? ConcurrentLinkedQueue是线程安全的无界非阻塞队列,其底层数据结构是使用单向…

03 Day Python数据类型

一:什么是数据? x10,10是我们要存储的数据 2 为何数据要分不同的类型 数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示 3 数据类型 数字 字符串 列表 元组 字典 集合 二:数字int #bit_length() 当十进…

border三角形阴影(不规则图形阴影)和多重边框的制作

前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新! 1. border的组合写法 border:border-width border-style border-color; border-width:边框宽度&#xff0…

JDK 8 Javadoc调整了方法列表

自开始以来, Javadoc输出基本上是静态HTML,具有导航链接和外观的简单样式表样式。 Java SE 7很长时间以来就看到Javadoc输出默认外观的第一个重大变化 ,现在看来JDK 8将在生成的Javadoc输出上引入新的变化。 在本文中,我将通过JDK…

hdp安装 不安装mysql_hdp安装及使用问题汇总(一)

1)安装HDP时,如果打印如下错误信息:[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)是由于系统的python版本过高,导致验证ssl失败,将python降级为2.7.5以下或修改每个安装节点的python证书验证配置文件…

PhotoSphereViewer 全景图

1网站地址:http://photo-sphere-viewer.js.org/markers.html#demo 2参数中文地址:https://www.cnblogs.com/big-tree/p/5933437.html 使用方法: /*** Initialize the viewer*/ var PSV new PhotoSphereViewer({ // main configuration panor…

常用Lunix命令

计算机 1.硬件系统 输入单元、输出单元、算术逻辑单元、控制单元、记忆单元 中央处理单元:CPU(算术逻辑单元、控制单元) 电源、主板、CPU、内存(RAM)、硬盘、(声卡、显卡、网卡)(集成…

angularJS constant和value

angularJS可以通过constant(name,value)和value(name,value)对于创建服务也是很重要的。 相同点是:都可以接受两个参数,name和value。 区别: 1.constant(name,value)可以将一个已经存在的变量值注册为服务,并将其注入到应用的其他…

让我们编写一个文档样式的Web服务

您可能知道,我们可以使用四种主要的Web服务样式。 它们如下: 文件/文学 包装的文件/文学 RPC /编码 RPC /文字 当然,现在不建议使用RPC /编码样式。 如果您有兴趣,可以在此处找到这篇非常全面的文章,以了解不同的…

linux 进入容器,查看和关闭进程

1,linux 查询容器 ID: docker ps 2,进入容器(退出 exec 命令用:[ctrlD] ,不会终止容器运行。退出 top 命令:ctrl C) docker exec -it c39c9d3898c0 /bin/bash 3,查询进程…

mysql表单查询_MySQL表单集合查询

表单查询简单查询SELECT语句查询所有字段指定所有字段:select 字段名1,字段名2,...from 表名;select * from 表名;查询指定字段select 字段名1,字段名2,...from 表名;按条件查询带关系运算符的查询SELECT 字段名1,字段名2,……FROM 表名WHERE…

解决阿里云OSS跨域问题

解决阿里云OSS跨域问题 现象 本人项目中对阿里云图片请求进行了两次,第一次通过img标签进行,第二次通过异步加载获取。第一次请求到图片,浏览器会进行缓存,随后再进行异步请求,保存跨域失效。 错误信息如下&#xff1a…

css之hover改变子元素和其他元素样式

参考地址&#xff1a;链接 表示下一级元素&#xff0c;>表示子元素 1 <!DOCTYPE html>2 <html>3 <head lang"en">4 <meta charset"UTF-8">5 <title></title>6 </head>7 8 <style>9 #a {co…

将JacpFX客户端与JSR 356 WebSockets一起使用

JSR 356 WebSockets是即将发布的JEE 7版本中令人兴奋的新功能之一&#xff0c;并且在其参考实现中包括Server-和Client API。 这使其非常适合在客户端与JavaFX集成。 JacpFX是JavaFX之上的RCP框架&#xff0c;它使用基于消息的方法与组件进行交互。 这种基于消息的方法使集成We…

nagios check_mysql uptime_nagios使用check_mysql监控mysql

如果没有check_mysql插件&#xff0c;需要安装Mysql数据库1、建立专用数据库&#xff1a; [rootsvr3 ~]#mysql -u root -pEnter password:Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 51910Server version: 5.5.3-m3-log Source di…

《精通Spring4.X企业应用开发实战》读后感第七章(AOP概念)

转载于:https://www.cnblogs.com/Michael2397/p/8068486.html

XHTML与HTML的区别

XHTML的语法较为严谨&#xff0c;拥有一定的规则&#xff0c;如果不遵循规则的话容易出错。但也不必太过担心&#xff0c;因为XHTML的规则并不太难&#xff0c;它和HTML4.01标准没有太多的不同。 需要注意的是以下几点&#xff1a; 1.XHTML标签必须被正确的关闭&#xff0c;即…

EC2上的ElasticSearch不到60秒

好奇地看到所有ElasticSearch轮奸是关于什么的&#xff1f; 想在没有大量肘部油脂的情况下看到它吗&#xff1f; 然后&#xff0c;朋友&#xff0c; 别再犹豫了-不到60秒&#xff0c;我将向您展示如何在AWS AMI上安装ElasticSearch 。 您首先需要一个AWS账户以及一个SSH密钥对…

Material使用04 MdCardModule和MdButtonModule综合运用

设计需求&#xff1a;设计一个登陆页面 1 模块导入 1.1 将MdCardModule和MdButtonModule模块导入到共享模块中 import { NgModule } from angular/core; import { CommonModule } from angular/common; import { MdSidenavModule, MdToolbarModule,MdIconModule,MdButtonModule…

mysql子分区多少层_MYSQL子分区修剪

我有一个MYSQL表与分区的年份和子分区的月份。MYSQL子分区修剪CREATE TABLE ptable (id INT NOT NULL AUTO_INCREMENT,name varchar(100),purchased DATETIME NOT NULL,PRIMARY KEY (id, purchased))PARTITION BY RANGE(YEAR(purchased))SUBPARTITION BY HASH(MONTH(purchased)…