数据库面试总结

1.存储过程

是什么?

咱们经常使用的关系型数据库是MySQL,操做数据库的语言通常为SQL语句,SQL在执行的时候须要要先编译,而后执行,而存储过程(Stored Procedure)是一组为了完成某种特定功能的SQL语句集,经编译后存储在数据库中,用户经过指定存储过程的名字并给定参数(若是该存储过程带有参数)来调用执行它html

一个存储过程是一个可编程的函数,它在数据库中建立并保存。它能够有SQL语句和一些特殊的控制结构组成。当但愿在不一样的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是很是有用的。数据库中的存储过程能够看作是对面向对象方法的模拟,它容许控制数据的访问方式。java

优势

1)存储过程是一个预编译的代码块,执行效率比较高;mysql

2)一个存储过程替代大量T_SQL语句 ,能够下降网络通讯量,提升通讯速率,即只须要传存储过程的名字和参数,不用传SQL语句;算法

3)能够必定程度上确保数据安全,存储过程可被做为一种安全机制来充分利用:系统管理员经过执行某一存储过程的权限进行限制,可以实现对相应的数据的访问权限的限制,避免了非受权用户对数据的访问,保证了数据的安全。sql

举例:数据库

 

-------------建立名为GetUserAccount的存储过程----------------
create Procedure GetUserAccount as
select * from UserAccount go

-------------执行上面的存储过程----------------
exec GetUserAccount

结果:至关于运行 select * from UserAccount 这行代码,结果为整个表的数据。编程

更多使用语法实例:http://www.cnblogs.com/knowledgesea/archive/2013/01/02/2841588.html安全

2,索引

  索引(Index)是帮助MySQL高效获取数据的数据结构;在数据以外,数据库系统还维护着知足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,能够在这些数据结构上实现高级查找算法,提升查询速度,这种数据结构,就是索引。网络

实现原理:https://www.cnblogs.com/xdyixia/p/9368691.html 数据结构

索引存储分类

索引是在MySQL的存储引擎层中实现的,而不是在服务层实现的。因此各类存储引擎支持的索引并不相同,MySQL目前提供了如下4种索引。

B-Tree 索引:最多见的索引类型,大部分引擎都支持B树索引。 
HASH 索引:只有Memory引擎支持,使用场景简单。 
R-Tree 索引(空间索引):空间索引是MyISAM的一种特殊索引类型,主要用于地理空间数据类型。 
Full-text (全文索引):全文索引也是MyISAM的一种特殊索引类型,主要用于全文索引,InnoDB从MySQL5.6版本提供对全文索引的支持。

B-TREE索引类型

普通索引 
这是最基本的索引类型,并且它没有惟一性之类的限制,能够经过如下几种方式建立: 
(1)建立索引: CREATE INDEX 索引名 ON 表名(列名1,列名2,…); 
(2)修改表: ALTER TABLE 表名 ADD INDEX 索引名 (列名1,列名2,…); 
(3)建立表时指定索引:CREATE TABLE 表名 ( […], INDEX 索引名 (列名1,列名 2,…) ); 

UNIQUE索引 
表示惟一的,不容许重复的索引,若某一字段的信息不能重复(例如身份证号),能够将该字段的索引设置为unique: 
(1)建立索引:CREATE UNIQUE INDEX 索引名 ON 表名(列名1,列名2,…); 
(2)修改表:ALTER TABLE 表名ADD UNIQUE 索引名 (列名1,列名2,…); 
(3)建立表时指定索引:CREATE TABLE 表名( […], UNIQUE 索引名 (列名1,列名2,…)); 

主键:PRIMARY KEY索引 
主键是一种惟一性索引,但它必须指定为“PRIMARY KEY”。能够将其理解为 索引名固定为 PRIMARY KEY 的 UNIQUE索引。 
(1)主键通常在建立表的时候指定:“CREATE TABLE 表名( […], PRIMARY KEY (列的列表) ); ”。 
(2)可是,咱们也能够经过修改表的方式加入主键:“ALTER TABLE 表名 ADD PRIMARY KEY (列的列表); ”。 
每一个表只能有一个主键。 (主键至关于聚合索引,是查找最快的索引) 
注:不能用CREATE INDEX语句建立PRIMARY KEY索引

经常使用语法

设置索引 
在执行CREATE TABLE语句时能够建立索引,也能够单独用CREATE INDEX或ALTER TABLE来为数据表增长索引。

1.ALTER TABLE - ALTER TABLE能够用来建立普通索引、UNIQUE索引或PRIMARY KEY索引。

ALTER TABLE table_name ADD INDEX index_name (column_list) ALTER TABLE table_name ADD UNIQUE index_name (column_list) ALTER TABLE table_name ADD PRIMARY KEY (column_list)

2.CREATE INDEX - CREATE INDEX可对表增长普通索引或UNIQUE索引。

CREATE INDEX index_name ON table_name (column_list) CREATE UNIQUE INDEX index_name ON table_name (column_list)

删除索引 
可利用ALTER TABLE或DROP INDEX语句来删除索引。相似于CREATE INDEX语句,DROP INDEX能够在ALTER TABLE内部做为一条语句处理,语法以下。

DROP INDEX index_name ON talbe_name ALTER TABLE table_name DROP INDEX index_name ALTER TABLE table_name DROP PRIMARY KEY

  其中,前两条语句是等价的,删除掉table_name中名为index_name的索引。 
  第3条语句只在删除PRIMARY KEY索引时使用,由于一个表只可能有一个PRIMARY KEY索引,所以不须要指定索引名。若是没有建立PRIMARY KEY索引,但表具备一个或多个UNIQUE索引,则MySQL将删除第一个UNIQUE索引。

  若是从表中删除了某列,则索引会受到影响。对于多列组合的索引,若是删除其中的某列,则该列也会从索引中删除。若是删除组成索引的全部列,则整个索引将被删除。

查看索引

mysql> show index from tblname;

设置索引的原则

  • 较频繁的做为查询条件的字段应该建立索引
  • 惟一性太差的字段不适合单首创建索引,即便频繁做为查询条件
  • 更新很是频繁的字段不适合建立索引
  • 不会出如今 WHERE 子句中的字段不应建立索引
  • 索引的选择性较低不宜建索引 
  • 注:所谓索引的选择性(Selectivity),是指不重复的索引值(也叫基数,Cardinality)与表记录数的比值,显然选择性的取值范围为(0, 1]:
SELECT count(DISTINCT(column_name))/count(*) AS Selectivity FROM table_name;

索引的弊端

  索引是有代价的:索引文件自己要消耗存储空间,同时索引会加剧插入、删除和修改记录时的负担,另外,MySQL在运行时也要消耗资源维护索引,所以索引并非越多越好。

3,B+ 树

  如上图,是一颗b+树,浅蓝色的块咱们称之为一个磁盘块,能够看到每一个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P一、P二、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即三、五、九、十、1三、1五、2八、2九、3六、60、7五、7九、90、99。非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如1七、35并不真实存在于数据表中。

b+树的查找过程

  如图所示,若是要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找肯定29在17和35之间,锁定磁盘块1的P2指针,内存时间由于很是短(相比磁盘的IO)能够忽略不计,经过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,经过指针加载磁盘块8到内存,发生第三次IO,同时内存中作二分查找找到29,结束查询,总计三次IO。真实的状况是,3层的b+树能够表示上百万的数据,若是上百万的数据查找只须要三次IO,性能提升将是巨大的,若是没有索引,每一个数据项都要发生一次IO,那么总共须要百万次的IO,显然成本很是很是高。

b+树性质

  1.经过上面的分析,咱们知道IO次数取决于b+树的高度h,假设当前数据表的数据量为N,每一个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N必定的状况下,m越大,h越小;而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,若是数据项占的空间越小,数据项的数量越多,树的高度越低。这就是为何每一个数据项,即索引字段要尽可能的小,好比int占4字节,要比bigint8字节少一半。这也是为何b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度降低,致使树增高。当数据项等于1时将会退化成线性表。 
  2.当b+树的数据项是复合的数据结构的时候,好比(name,age,sex),b+树是按照从左到右的顺序来创建搜索树的,好比当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来肯定下一步的所搜方向,若是name相同再依次比较age和sex,最后获得检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪一个节点,由于创建搜索树的时候name就是第一个比较因子,必需要先根据name来搜索才能知道下一步去哪里查询。好比当(张三,F)这样的数据来检索时,b+树能够用name来指定搜索方向,但下一个字段age的缺失,因此只能把名字等于张三的数据都找到,而后再匹配性别是F的数据了, 这个是很是重要的性质,即索引的最左匹配特性

4.事务

  事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操做序列,由一条或者多条sql语句组成,这些操做要么都执行,要么都不执行,它是一个不可分割的工做单位。

ACID特性

事务应该具备4个属性:原子性、一致性、隔离性、持久性。

原子性(Atomicity):指整个数据库事务是不可分割的工做单位。只有事务中全部的数据库操做都执行成功,整个事务的执行才算成功。事务中任何一个sql语句执行失败,那么已经执行成功的sql语句也必须撤销,数据库状态应该退回到执行事务前的状态。 

一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另外一个一致状态。一致状态的含义是数据库中的数据应知足完整性约束,也就是说在事务开始以前和事务结束之后,数据库的完整性约束没有被破坏 。

隔离性(Isolation):隔离性也叫作并发控制、可串行化或者锁。事务的隔离性要求每一个读写事务的对象与其它事务的操做对象能相互分离,即该事务提交前对其它事务都不可见,这一般使用锁来实现多个事务并发执行时,一个事务的执行不该影响其余事务的执行。 

持久性(Durability):表示事务一旦提交了,其结果就是永久性的,也就是数据就已经写入到数据库了,若是发生了宕机等事故,数据库也能将数据恢复。

事务的分类

事务分为一下5类:

  1. 扁平事务;
  2. 带有保存点的扁平事务;
  3. 链事务;
  4. 嵌套事务;
  5. 分布式事务。

1)扁平事务 
  扁平事务是最简单的一种,也是实际开发中使用的最多的一种事务。在这种事务中,全部操做都处于同一层次,最多见的方式以下:

BEGIN WORK Operation 1 Operation 2 Operation 3 ... Operation N COMMIT WORK

或者

BEGIN WORK Operation 1 Operation 2 Operation 3 ... Operation N (Error Occured) ROLLBACK WORK

  扁平事务很简单,但有一个主要缺点是不能提交或回滚事务的某一部分,或者分几个独立的步骤去提交。好比有这样的一个例子,我从呼和浩特去深圳,为了便宜,我可能这么干:

BEGIN WORK Operation1:呼和浩特---火车--->北京
     Operation2:北京---飞机--->深圳
 ROLLBACK WORK

  可是,若是在Operation1中,从呼和浩特到北京的火车晚点了,错过了飞往深圳的航班,怎么办? 
  由于扁平事务的特性,那我就须要回滚,我须要再回到呼和浩特,这样作的成本过高,因此就有了下面的第二种事务——带有保存点的扁平事务。

2)带有保存点的扁平事务 
  这种事务除了支持扁平事务支持的操做外,容许在事务执行过程当中回滚到同一事务中较早的一个状态,这是由于可能某些事务在执行过程当中出现的错误并不会对全部的操做都无效,放弃整个事务不合乎要求,开销也太大。保存点用来通知系统应该记住事务当前的状态,以便之后发生错误时,事务能回到该状态。

3)链事务 
  链事务,就是指回滚时,只能恢复到最近一个保存点;而带有保存点的扁平事务则能够回滚到任意正确的保存点。

4)嵌套事务

经过下面实例来讲明什么叫嵌套事务

BEGIN WORK SubTransaction1: BEGIN WORK SubOperationX COMMIT WORK SubTransaction2: BEGIN WORK SubOperationY COMMIT WORK ... SubTransactionN: BEGIN WORK SubOperationN COMMIT WORK
 COMMIT WORK

  这就是嵌套事务,在事务中再嵌套事务,位于根节点的事务称为顶层事务。事务的前驱称为父事务,事务的下一层称为子事务。

  子事务既能够提交也能够回滚,可是它的提交操做并不立刻生效除非由其父事务提交。所以就能够肯定,任何子事务都在顶层事务提交后才真正的被提交了。同理,任意一个事务的回滚都会引发它的全部子事务一同回滚

5)分布式事务 
  分布式事务一般是指在一个分布式环境下运行的扁平事务,所以须要根据数据所在位置访问网络中的不一样节点,好比:经过建设银行向招商银行转帐,建设银行和招商银行确定用的不是同一个数据库,同时两者的数据库也不在一个网络节点上,那么当用户跨行转帐,就是经过分布式事务来保证数据的ACID的。

在MySQL中使用事务

在MySQL命令行的默认设置下,事务都是自动提交的,即执行SQL语句后就会立刻执行COMMIT操做。所以要显示地开启一个事务须使用命令BEGIN或START TRANSACTION,或者执行命令SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。

来看看咱们可使用哪些事务控制语句。

  • BEGIN或START TRANSACTION;显示地开启一个事务;
  • COMMIT;也可使用COMMIT WORK,不过两者是等价的。COMMIT会提交事务,并使已对数据库进行的全部修改称为永久性的;
  • ROLLBACK;有可使用ROLLBACK WORK,不过两者是等价的。回滚会结束用户的事务,并撤销正在进行的全部未提交的修改;
  • SAVEPOINT identifier;SAVEPOINT容许在事务中建立一个保存点,一个事务中能够有多个SAVEPOINT;
  • RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
  • ROLLBACK TO identifier;把事务回滚到标记点;
  • SET TRANSACTION;用来设置事务的隔离级别。

并发访问数据库是可能会出现的问题

更新丢失:当有两个并发执行的事务,更新同一行数据,那么有可能一个事务会把另外一个事务的更新覆盖掉。当数据库没加任何锁操做的状况下会发生。

脏读:一个事务读取到了另一个事务没有提交的数据; 

  好比:事务T1更新了一行记录的内容,可是并无提交所作的修改。事务T2读取到了T1更新后的行,而后T1执行回滚操做,取消了刚才所作的修改。如今T2所读取的行就无效了; 

不可重复读:在同一事务中,屡次同一数据,读到的数据不一样(该数据被另外一个已经提交的事务修改); 
  好比:事务T1读取一行记录,紧接着事务T2修改(update)了T1刚才读取的那一行记录。而后T1又再次读取这行记录,发现与刚才读取的结果不一样。这就称为“不可重复”读,由于T1原来读取的那行记录已经发生了变化; 

幻读:同一事务中,根据相同的查询条件查询,从新执行查询时,返回的记录与前一次查询记录不一样; 
  好比:事务T1读取一条指定的WHERE子句所返回的结果集。而后事务T2新插入或删除(insert,delete)一行记录,这行记录刚好能够知足T1所使用的查询条件中的WHERE子句的条件。而后T1又使用相同的查询再次对表进行检索,可是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,由于对T1来讲这一行就像忽然出现的同样。 

事务的隔离级别

  在数据库操做中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。 InnoDB存储引擎提供的事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable 、read 、Serializable ,这四个级别能够逐个解决脏读 、不可重复读 、幻读 这几类问题。

1. Read uncommitted 读未提交
  在该级别下,一个事务对一行数据修改的过程当中,不容许另外一个事务对该行数据进行修改,但容许另外一个事务对该行数据读。所以本级别下,不会出现更新丢失,但会出现脏读、不可重复读、幻读。

2. Read committed 读提交
  在该级别下,未提交的写事务不容许其余事务访问该行,所以不会出现脏读;可是读取数据的事务容许其余事务的访问该行数据,所以会出现不可重复读的状况。
3. Repeatable read 重复读
  在该级别下,读事务禁止写事务,但容许读事务,所以不会出现同一事务两次读到不一样的数据的状况(不可重复读),且写事务禁止其余一切事务
4. Serializable 序列化
  该级别要求全部事务都必须串行执行,所以能避免一切因并发引发的问题,但效率很低。

  隔离级别越低,事务请求的锁越少或保持锁的时间就越短。InnoDB存储引擎默认的支持隔离级别是REPEATABLE READ;在这种默认的事务隔离级别下已经能彻底保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE级别隔离。固然咱们也能够在应用程序中再进行加锁控制。

开发中必备:

JDBC中设置事务级别,即java中的事务级别,能够看到第4级别就对应repeatable read;
Connection.setTransactionIsolation(int level);咱们用masql数据库通常直接用mysql默认隔离级别就行,不用在JDBC中再设

5.视图

  视图是一种虚拟的表,具备和物理表相同的功能,能够对视图进行增,改,查操做,视图一般是有一个表或者多个表的行或列的子集,对视图的修改不影响基本表,它使得咱们获取数据更容易,相比多表查询。

6.超键 候选键 主键 外键

超键:在关系中能惟一标识元组(数据库中的一条记录)的属性集称为关系模式的超键。一个属性能够为做为一个超键,多个属性组合在一块儿也能够做为一个超键。超键包含候选键和主键。 

候选键:是最小超键,即没有冗余元素的超键。 

主键:数据库表中对储存数据对象予以惟一和完整标识的数据列或属性的组合,用户选做元组标识的一个侯选键称为主键。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。

外键:在一个表中存在的另外一个表的主键称此表的外键,外键主要是用来描述两个表的关系。

7.三个范式

第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。

第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的状况),也即全部非关键字段都彻底依赖于任意一组候选关键字。 

第三范式(3NF):在第二范式的基础上,数据表中若是不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如 果存在”A → B → C”的决定关系,则C传递函数依赖于A。所以,知足第三范式的数据库表应该不存在以下依赖关系: 关键字段 → 非关键字段 x → 非关键字段y。

8.E-R图

E-R图也称实体-联系图(Entity Relationship Diagram),提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型。

E-R方法是“实体-联系方法”(Entity-Relationship Approach)的简称。它是描述现实世界概念结构模型的有效方法,是表示概念模型的一种方式,用矩形表示实体型,矩形框内写明实体名;用椭圆表示实体的属性,并用无向边将其与相应的实体型链接起来;用菱形表示实体型之间的联系,在菱形框内写明联系名,并用无向边分别与有关实体型链接起来,同时在无向边旁标上联系的类型(1:1,1:n或m:n)。

9.处理重复记录的经常使用操做

(1)查找表中多余的重复记录,重复记录是根据单个字段(column_name)来判断。

select * from table_name where column_name in (select column_name from table_name group by column_name having count(column_name) > 1)

(2)删除表中多余的重复记录,重复记录是根据单个字段(column_name)来判断,只留有id最小的记录。

delete from table_name where column_name in (select b.column_name from (select column_name from table_name group by column_name having count(column_name)>1)b);

(3)查找表中多余的重复记录(多个字段)。

select * from table_name a where (a.column_name1,a.column_name2) in (select column_name1,column_name2 from vitae group by column_name1,column_name2 having count(*) > 1)

(4)删除表中多余的重复记录(多个字段),只留有rowid最小的记录 。

delete from table_name a where (a.column_name1,a.column_name2) in (select column_name1,column_name2 from table_name group by column_name1,column_name2 having count(*) > 1) and rowid not in (select min(rowid) from table_name group by column_name1,column_name2 having count(rowid)>1)

10,MyISAM与InnoDB的区别是什么?

1)存储结构

MyISAM:每一个MyISAM表在磁盘上存储成三个文件,文件的名字以表的名字开始,扩展名指出文件类型:.frm文件存储表定义;数据文件的扩展名为.MYD (MYData);索引文件的扩展名是.MYI (MYIndex)。 
InnoDB:全部的表都保存在同一个数据文件中(也多是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操做系统文件的大小,通常为2GB。

2)存储空间

MyISAM:可被压缩,存储空间较小。支持三种不一样的存储格式:静态表(默认,可是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。 
InnoDB:须要更多的内存和存储,它会在主内存中创建其专用的缓冲池用于高速缓冲数据和索引。

3)可移植性、备份及恢复

MyISAM:数据是以文件的形式存储,因此在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操做。 
InnoDB:免费的方案能够是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

4)事务支持

MyISAM:强调的是性能,每次查询具备原子性,其执行数度比InnoDB类型更快,可是不提供事务支持。 
InnoDB:支持事务,外部键等高级数据库功能。 具备事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

这一点是很是重要。事务是一种高级的处理方式,如在一些列增删改中只要哪一个出错还能够回滚还原,而MyISAM就不能够了。

5)AUTO_INCREMENT

MyISAM:能够和其余字段一块儿创建联合索引。引擎的自动增加列必须是索引,若是是组合索引,自动增加能够不是第一列,他能够根据前面几列进行排序后递增。 
InnoDB: InnoDB中必须包含只有该字段的索引。引擎的自动增加列必须是索引,若是是组合索引也必须是组合索引的第一列。

6)表锁差别

MyISAM:只支持表级锁,用户在操做myisam表时,select,update,delete,insert语句都会给表自动加锁,若是加锁之后的表知足insert并发的状况下,能够在表的尾部插入新的数据。 
InnoDB:支持事务和行级锁,是innodb的最大特点。行锁大幅度提升了多用户并发操做的性能。可是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的

7)全文索引

MyISAM:支持 FULLTEXT类型的全文索引。 
InnoDB:不支持FULLTEXT类型的全文索引,可是innodb可使用sphinx插件支持全文索引,而且效果更好。

8)表主键

MyISAM:容许没有任何索引和主键的表存在,索引都是保存行的地址。 
InnoDB:若是没有设定主键或者非空惟一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。

9)表的具体行数

MyISAM:保存有表的总行数,若是select count() from table;会直接取出出该值。 
InnoDB:没有保存表的总行数,若是使用select count() from table;就会遍历整个表,消耗至关大,可是在加了wehre条件后,myisam和innodb处理的方式都同样。

10)CURD操做

MyISAM:若是执行大量的SELECT,MyISAM是更好的选择。 
InnoDB:若是你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除,在innodb上若是要清空保存有大量数据的表,最好使用truncate table这个命令。

11) 外键

MyISAM:不支持 
InnoDB:支持 
  经过上述的分析,基本上能够考虑使用InnoDB来替代MyISAM引擎了,缘由是InnoDB自身不少良好的特色,好比事务支持、存储 过程、视图、行级锁定等等,在并发不少的状况下,相信InnoDB的表现确定要比MyISAM强不少。另外,任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优点。若是不是很复杂的Web应用,非关键应用,仍是能够继续考虑MyISAM的,这个具体视状况而定。 

11,乐观锁 与 悲观锁

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和一致性以及数据库的统一性。

乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制采用的主要技术手段。

不管是悲观锁仍是乐观锁,都是人们定义出来的概念,能够认为是一种思想。其实不只仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有相似的概念。像java并发中的CAS操做也是乐观锁的一种实现

针对不一样的业务场景,应该选用不一样的并发控制方式。因此,不要把乐观并发控制和悲观并发控制狭义的理解为仅在DBMS中存在的概念,更不要把他们和数据库中提供的锁机制(行锁、表锁、排他锁、共享锁)混为一谈。其实,在DBMS中,悲观锁正是利用数据库自己提供的锁机制来实现的。

悲观锁

  在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它能够阻止一个事务以影响其余用户的方式来修改数据。若是一个事务执行的操做在某行数据上应用了锁,那只有当这个事务把锁释放,其余事务才可以执行与该锁冲突的操做。

  悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本低于回滚事务的成本的环境中

悲观锁:正如其名,它指的是对数据被外界(包括本系统当前的其余事务,以及来自外部系统的事务处理)修改持保守态度(悲观),所以,在整个数据处理过程当中,将数据处于锁定状态。 悲观锁的实现,每每依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,不然,即便在本系统中实现了加锁机制,也没法保证外部系统不会修改数据)。

悲观锁的流程: 
1.在对某一记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。 
2.若是加锁失败,说明该记录正在被修改,那么当前操做可能要等待或者抛出异常, 具体响应方式由开发者根据实际状况决定。 
3.若是成功加锁,那么就能够对记录作修改,事务完成后就会解锁了。 
4.其间若是有其余事务要对该记录作修改或加排他锁,都会等待该事务将该记录解锁或直接抛出异常。

MySQL InnoDB中使用悲观锁

注意:要使用悲观锁,必须先关闭mysql数据库的自动提交功能,由于MySQL默认使用autocommit模式,也就是说,当你执行一个更新操做后,MySQL会马上将结果进行提交。

set autocommit=0;
//0.开始事务 begin;/begin work;/start transaction; (三者选一就能够) //1.查询出商品信息 select status from t_goods where id=1 for update; //2.根据商品信息生成订单 insert into t_orders (id,goods_id) values (null,1); //3.修改商品status为2 update t_goods set status=2; //4.提交事务 commit;/commit work;

  上面的查询语句中,咱们使用了select…for update的方式,这样就经过开启排他锁的方式实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被咱们锁定了,其它事务必须等本次事务提交以后才能对该记录进行操做。这样咱们能够保证当前的数据不会被其它事务修改。

注意:上面提到,使用select…for update会把数据给锁住,不过咱们须要注意一下锁的级别,MySQL InnoDB默认为行级锁。行级锁都是基于索引的,若是一条SQL语句没有用到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点须要注意。

优势与不足: 
优势:悲观并发控制其实是采用“先取锁再访问”的保守策略,为数据处理的安全性提供了保证; 
缺点:在效率方面,处理加锁的机制会让数据库产生额外的开销,同时会增长产生死锁的机率;另外,在只读型事务中因为不会产生冲突,也不必使用锁,这样作只会增长系统负载;还会下降并行性,一个事务若是锁定了某行数据,其余事务就必须等待该事务处理完才能够处理那行数

乐观锁

  在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理数据时不会彼此互相影响,各事务可以在不产生锁的状况下处理各自影响的那部分数据。在提交数据更新以前,每一个事务会先检查在该事务读取数据后,有没有其余事务对该数据作过修改。若是其余事务更新过该数据的话,正在提交的事务会进行回滚(这正是CAS操做的思想)。乐观事务控制最先是由孔祥重(H.T.Kung)教授提出。

  乐观锁( Optimistic Locking )是相对悲观锁而言,乐观锁假设数据通常状况下不会形成冲突,因此在事务对数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,若是发现冲突了,则返回错误信息,让用户决定如何去作。

  相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制,通常用记录数据版本的方式实现乐观锁。

  数据版本:为数据增长的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,便对版本标识进行一次更新。当事务提交更新的时候,须要判断数据库表对应记录的当前版本信息与第一次取出来的版本标识是否一致,若是数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,不然认为是过时数据。

  实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。

使用版本号实现乐观锁

  使用版本号时,能够在数据初始化时指定一个版本号,每次对数据的更新操做都对版本号执行+1操做。并判断当前版本号是否是该数据的最新的版本号。

1.查询出商品信息 select (status,status,version) from t_goods where id=#{id} 2.根据商品信息生成订单 3.修改商品status为2 update t_goods set status=2,version=version+1
where id=#{id} and version=#{version};

        乐观并发控制假设事务之间的数据竞争(data race)几率比较小,所以尽量直接作下去,直到提交的时候才去锁定,因此不会产生任何锁和死锁。但若是直接简单这么作,仍是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,通过修改之后写回数据库,这时就遇到了问题。

 

https://blog.csdn.net/xiaomingdetianxia/article/details/72475924

https://zhuanlan.zhihu.com/p/23713529