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是线程安全的无界非阻塞队列,其底层数据结构是使用单向…

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…

angularJS constant和value

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

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

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

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

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

Material使用04 MdCardModule和MdButtonModule综合运用

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

python实现bp神经网络对csv文件进行数据预测

参考资源: sklearn库 bp神经网络[从原理到代码一篇搞定](2)_sklearn 神经网络-CSDN博客 十分钟上手sklearn:安装,获取数据,数据预处理 - 知乎 (zhihu.com) 一个实例讲解如何使用BP神经网络(附代码) - 知…

Spring MVC:表单处理卷。 4 –单选按钮

在软件开发领域,单选按钮是图形用户界面的重要组成部分。 Spring MVC标签库为此表单元素提供了特殊标签。 更确切地说,有两个标签用于此目的:单选按钮,单选按钮。 两者对于特定任务都是有用的。 如您所知,我将在帖子中…

点击时候确定某个元素 js_某空气质量监测平台 JS反爬

目标:中国空气质量在线监测分析平台|城市分析 参考CSDN中文章,记录一下学习过程通过切换城市,页面数据是通过 Ajax 加载的,数据接口:https://www.aqistudy.cn/apinew/aqistudyapi.php请求的POST Data、返回的数据都被加…

HTML 部分常用属性、组成属性|...超链接、路径、锚点、列表、滚动、URL编码、表格、表单、GET和POST

URL地址 就是我们所说的网址:www.jd.com 浏览器内核,渲染引擎 Ie内核:triteent 谷歌/欧鹏:blink 火狐:gecko 苹果:webkit 渲染引擎是出现兼容性的根本问题 -html概念:hyper Text Markup Languag…

Spring @Value取值为null或@Autowired注入失败

Value 用于注入.properties文件中定义的内容 Autowired 用于装配bean 用法都很简单,很直接,但是稍不注意就会出错。下面就来说说我遇到的问题。 前两天在项目中遇到了一个问题,大致描述就是我写了如下一个类(只列出关键代码&#…

mysql 部门表_MySQL高级

本文大纲环境win10-64MySQL Community Server 5.7.1mysqld –version可查看版本官方文档SQL执行顺序手写顺序我们可以将手写SQL时遵循的格式归结如下&#xff1a;select distinct from join on wheregroup byhavingorder bylimit <offset>,<rows>distinct&…

使用Apache Camel发布/订阅模式

发布/订阅是一种简单的消息传递模式&#xff0c;其中&#xff0c;发布者将消息发送到某个频道&#xff0c;而无需知道谁将接收消息。 然后&#xff0c;通道负责将消息的副本传递给每个订户。 此消息传递模型允许创建松耦合和可伸缩的系统。 这是一种非常常见的消息传递模式&am…

移动端(H5)弹框组件--简单--实用--不依赖jQuery

俗话说的好&#xff0c;框架是服务与大家的&#xff0c;包含的功能比较多&#xff0c;代码多。在现在追求速度的年代。应该根据自己的需求去封装自己所需要的组件。 下边就给大家介绍一下自己封装的一个小弹框组件&#xff0c;不依赖与jQuery&#xff0c;代码少&#xff0c;适…

c++ for循环 流程图_python 零基础必知--条件控制与循环语句

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理本文章来自腾讯云 作者&#xff1a;somenzz如果没有 if 语句和循环语句&#xff0c;请问你怎么编程&#xff1f;Python 中的条件控制和循环语句都非常简单&…

前端总结·基础篇·CSS(二)视觉

前端总结系列 前端总结基础篇CSS&#xff08;一&#xff09;布局前端总结基础篇CSS&#xff08;二&#xff09;视觉前端总结基础篇CSS&#xff08;三&#xff09;补充前端总结基础篇JS&#xff08;一&#xff09;原型、原型链、构造函数和字符串&#xff08;String&#xff09;…

【kindle笔记】之 《浪潮之巅》- 2018-1-

《浪潮之巅》 这本书推荐自最爱的政治课老师。 政治课老师张巍老师。我会一直记得你的。 以这样的身份来到这个学校&#xff0c;他人的质疑&#xff0c;自己的忐忑&#xff0c;老板的不公。犹犹豫豫谨小慎微地前进。 第一次听到这样的话是从您口中&#xff1a; 在座的诸位&…

Secure CRT 自动记录日志log配置

SecureCRT8.0的下载地址下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1i5q09qH 密码&#xff1a;4pa2 配置自动log操作如下&#xff1a; 1.options ---> Session Options 2. 设置log 文件属性 点击 日志 &#xff0c;在选项框中 Log file name中填入路径和…

禁用mysql的sleep函数_MySQL的sleep函数的特殊特现象

MySQL中的系统函数sleep&#xff0c;实际应用的场景不多&#xff0c;一般用来做实验测试&#xff0c;昨天在测试的时候&#xff0c;意外发现sleep函数的一个特殊现象。如果在查询语句中使用sleep函数&#xff0c;那么休眠的时间跟返回的记录有关。如下测试所示&#xff1a;mysq…