做公司网站需要的材料有哪些,seo在线优化系统,抖音代运营广州,网站推广产品一、mysql数据库中的存储引擎mysql在创建数据表时可以通过engine关键字设置存储引擎的类型#xff0c;也可以通过alter命令来修改表的存储引擎。可以通过show engines命令来查看当前mysql数据库支持的存储引擎的类型#xff0c;一般场景的存储引擎有#xff1a;InnoDB、MyIS…一、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)。共享锁就是读锁允许事务读一行数据。排它锁就是写锁允许事务删除或更新一行数据。量中锁的兼容性如下图所示。此外InnoDB中还有一种被称为意向锁的锁这种锁是由引擎自动添加和释放的所以操作十分快对用户而言可以认为是透明的。意向锁存在的目的是为数据库提供多粒度的上锁例如当为一个行数据添加行锁时先对数据所在的表和页添加表级和页级的意向锁这样如果在表级或者页级就出现冲突则不用在去检测行数据的锁兼容性了可以减少冲突检测的代价提高上锁的效率。一般行级锁是不会与意向锁冲突的。意向锁与读写锁的兼容性如下图所示。五、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 a1 and b5 for update;接下来在连接B中开启事务执行如下命令。select * from t2 where a1 and b1 for update;执行结果如下图所示。可以看出在执行连接A中的事务时虽然查询结果只有一行但实际上是锁了两行记录这就是因为InnoDB存储引擎中是使用锁索引的方法来实现行锁的。而上面的t2表中只有a列有索引所以当执行连接A中的事务时存储引擎实际上是对a列值为1的数据都进行了锁定所以锁了两行数据。而如果表中没有索引那么InnoDB就无法实现行锁了每次锁定都将锁定表中的所有数据就和表锁一样了。因此一般在update和delete操作中where条件中推荐使用自增主键来作为筛选条件这样可以保证每次只锁定一行数据。八、InnoDB的gap lockInnoDB的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 a27 for update;接下来在连接B中开启事务执行如下命令。insert into t3 values(27);结果如下图所示。可以看出在连接B中27无法插入t3表中。这样就解决了幻读问题。看似很完美但是之际上InnoDB中锁定的是(23,30)这样的数值范围不知27无法插入了连24、25、26、28、29都无法插入了。如果在B连接中执行如下语句。insert into t3 values(28);insert into t3 values(25);结果如下图。因此在gap lock下数据库的并发性是比较差的因为每次都会锁掉一个范围内的数据。当然解决的方法也很简单就是采用自增主键update和delete的时候where条件中根据自增主键来定位数据这样就能保证每次数据库只锁定一行数据。九、死锁死锁是指两个或两个以上的事务再执行过程中因争夺资源而造成的一种相互等待的现象。mysql中等待图的方式来检查是否存在死锁的情况如果存在死锁则选择回滚代价最小的事务进行回滚。虽然mysql中可以自动检测死锁但是在实际开发中还是要尽量的避免死锁否则并发效率会收到极大的影响。常用的预防死锁的方法有1. 尽可能缩短事务的长度单步事务是永远不会出现死锁的。2. 可能存在冲突的跨表事务尽量避免并发。3. 进行批量更新操作时尽量用自增主键来作为选择条件并对主键值进行排序这样就不会造成死锁了。举例来说如果两个连接同时执行一下语句是不会有死锁的。update tb_goods set store_quantitystore_quantity 10 where goods_id1;update tb_goods set store_quantitystore_quantity 10 where goods_id3;update tb_goods set store_quantitystore_quantity 10 where goods_id7;update tb_goods set store_quantitystore_quantity 10 where goods_id9;因为where中用的是自增主键且语句中的主键值是递增的这样多个事务中是不会出现循环锁定的。如果两个事务分别执行如下语句则可能出现死锁。事务Aupdate tb_goods set store_quantitystore_quantity 10 where goods_id1;update tb_goods set store_quantitystore_quantity 10 where goods_id3;update tb_goods set store_quantitystore_quantity 10 where goods_id7;update tb_goods set store_quantitystore_quantity 10 where goods_id9;事务Bupdate tb_goods set store_quantitystore_quantity 10 where goods_id3;update tb_goods set store_quantitystore_quantity 10 where goods_id1;update tb_goods set store_quantitystore_quantity 10 where goods_id7;update tb_goods set store_quantitystore_quantity 10 where goods_id9;当两个事务同事执行完第一个更新语句主键值为1和3的行并锁定接下来两个事务在分别请求主键值为1和3的行就出现了循环等待也就是死锁。死锁存在的条件有三个1.有两个以上的并发修改的事务2. 多个事务都是多步的3. 多步操作中想抢占的锁资源存在并发关系。只要破坏这三个条件中的任意一个则死锁就可以避免。当线上数据库出现大量死锁就需要进行排查排查时不止要检查死锁出现的sql语句还有检查触发改sql语句的上下文以及具体的业务逻辑根据上下文语句的加锁范围分析存在争用的记录从而定位死锁出现的原因。十、事务的组织以简单的一个购物业务场景为例流程图如下。简单来说就是用先想买商品1那么先检查商品1是否有库存如果有就将若干件商品1加入用户订单。接下来用户还想买商品2那么再检查商品2是否有库存如果有就将若干件商品2加入用户订单。最后用户确认提交订单并付款就完成了购物的操作。这里需要用事务和锁来实现业务需求原因有两个。1. 因为业务需要保证操作的原子性查询库存、更新订单和扣除库存要么都成功要么都不成功所以要用事务。2. 要避免业务纠纷业务中查询库存到扣除库存的过程中不能让库存再发生变化因此要用锁在查询库存的时候用for update人工加锁。最简单的是用一个大事务来实现业务需求如下图所示。这样固然是可以保证业务的原子性的确保库存不会被扣成负的。但是在实际业务中往往用户在挑选完商品1后到用户再添加商品2这之间所间隔的时间是非常长的这样会导致在很长的时间内只有一个人可以买商品1这显然是不合理的。此外如果用户挑选完商品1后连接意外中断了当用户在重新连接回来后之前的未完成订单是找不到的这肯定也是不能让人接受的。因此需要对上面的大事务进行优化将一个大事务切分为若干个小事务例如上面的事物可以切分为三个小事务一个是添加商品1的事务一个是添加商品2的事务最后是提交付款的事务如下图所示。如果是一个简单的购物网站到这里就已经可以满足购物业务的需求了。但是像那行大的电商网站这样还是不行的因为可以每个商品下还有各种优惠、特价等这样当将一个商品添加到订单中时不仅仅要检查是否有库存还要检查是否有什么优惠、特价等等这样事务就又变长了商品锁定的时间又变长了这对于大型电商网站是不能接受的因此需要进一步优化。优化的方法也很简单就是在用select检查库存时不用for update进行锁定了而在执行update操作时添加一个判断条件就是判断库存是否够如下图所示。可能有人会疑问既然这样那为什么还要在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具体在执行什么因此需要与业务确认看是否可以直接杀死连接。