Java面试题(二)–MySQL

1 存储引擎

1、简单描述一个Mysql的内部结构?

MySQL的基本架构示意图:

Java面试题(二)--MySQL
大体来说,MySQL可以分为 server层存储引擎层两部分。

① server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能

② 存储引擎层: 存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎

连接器:连接器负责跟客户端建立连接、获取权限、维持和管理连接。

查询缓存:连接建立完成后,你就可以执行select语句了,此时会先进行查询缓存(缓存是key-value格式;key是sql语句,value是sql语句的查询结果)。

分析器

​ 1、词法分析: MySQL需要识别出里面的字符串分别是什么,代表什么。

​ 2、语法分析:根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。

优化器:优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。

执行器:调用存储引擎接口,执行sql语句,得到结果

2、数据库存储引擎有哪些?(高频)

MySQL提供了 插件式的存储引擎架构。所以MySQL存在多种存储引擎,可以根据需要使用相应引擎,或者编写存储引擎。存储引擎是基于表的,而不是基于库的。所以存储引擎也可被称为表类型。MySQL5.0支持的存储引擎包含 : InnoDB 、MyISAM 、BDB、MEMORY、MERGE、EXAMPLE、NDB Cluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED 等,其中 InnoDBBDB提供事务安全表,其他存储引擎是非事务安全表。

3、InnoDB与MyISAM的区别?(高频)

1、InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;

2、InnoDB支持外键,而MyISAM不支持。

3、InnoDB是支持表锁和行级锁,MyISAM只支持表锁

4、如何选择存储引擎?

如果没有特别的需求,使用默认的 Innodb 即可。

MyISAM:以读为主的应用程序,比如博客系统、新闻门户网站。

Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。比如OA自动化办公系统。

5、存储引擎常用命令?

show engines;  查看MySQL提供的所有存储引擎

Java面试题(二)--MySQL
创建新表时如果不指定存储引擎,那么系统就会使用默认的存储引擎,MySQL5.5之前的默认存储引擎是MyISAM,5.5之后就改为了InnoDB。
show variables like '%storage_engine%';  查看mysql默认的存储引擎

Java面试题(二)--MySQL
show table status like "table_name"\G   查看表的存储引擎

Java面试题(二)--MySQL

2 索引

6、什么是索引?(高频)

MySQL官方对索引的定义为: 索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。如下面的示意图所示 :

Java面试题(二)--MySQL
左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并不是一定物理相邻的)。为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找快速获取到相应数据。一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以 索引文件的形式 存储在磁盘上。索引是数据库中用来 提高性能的最常用的工具。

导入资料中提供的sql脚本文件,已经准备了1000W条数据。

A. 根据ID查询

select * from tb_sku where id = 1999\G ;

Java面试题(二)--MySQL
查询速度很快, 接近0s , 主要的原因是因为id为主键, 有索引;

查看执行计划:

Java面试题(二)--MySQL
B. 根据 name进行精确查询
select * from tb_sku where name = '华为Meta1999'\G ;

Java面试题(二)--MySQL
查询速度太慢了,几乎使用了9s才完成数据的查询。

查看执行计划:

Java面试题(二)--MySQL

7 什么是聚簇索引和非聚簇索引?(高频)

聚簇索引:将数据和索引放在一起,并且是按照一定顺序组织的,找到索引也就找到了数据。一般情况下主键就是默认的聚簇索引

Java面试题(二)--MySQL
优缺点:采用集群电缆引入行数据查询效率高,更新数据效率低,会占用较大的存储空间。
[En]

Advantages and disadvantages: the use of cluster cable to introduce row data query efficiency is high, the efficiency of updating data is low, and it will occupy a large storage space.

非聚簇索引:叶子结点不存储数据,存储的是行的物理地址,在进行行数据查询的时候,需要根据物理地址值从数据库表中再次进行查询【回表】

Java面试题(二)--MySQL

优缺点:使用非聚集索引查询行数据效率较低,更新数据效率较高,同时占用存储空间较少。

[En]

Advantages and disadvantages: using non-clustered index to query row data is inefficient, updating data is more efficient, and taking up less storage space at the same time.

8、如何创建索引?(高频)

为了提升上述查询效率,可以对name字段创建索引。创建索引有两种方式:

1、方式一:在创建表的时候创建索引

-- 语法结构
CREATE TABLE  表名( 属性名 数据类型[完整性约束条件],
    属性名 数据类型[完整性约束条件],
    ......

    属性名 数据类型
    [ UNIQUE | FULLTEXT | SPATIAL ]  INDEX | KEY
    [ 别名]  ( 属性名1  [(长度)]  [ ASC | DESC] )
);

示例:

-- 示例代码
CREATE TABLE index1 (
  id int(11) DEFAULT NULL,
  name varchar(20) DEFAULT NULL,
  sex tinyint(1) DEFAULT NULL,
  KEY index1_id (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

2、方式二:使用create index语句进行索引创建

语法:

CREATE  [UNIQUE|FULLTEXT|SPATIAL]  INDEX index_name
[USING  index_type]
ON tbl_name(index_col_name,...)   // 如果指定的列的名称是多个,那么这个索引我们将其称之为复合索引

示例:

create index idx_name on tb_sku(name) ;

Java面试题(二)--MySQL
再次进行查询:
Java面试题(二)--MySQL
通过explain , 查看执行计划,执行SQL时使用了刚才创建的索引
Java面试题(二)--MySQL

9、常见的索引约束有哪些?(高频)

1、UNIQUE:唯一索引

​ 表示唯一的,不允许重复的索引,如果该字段信息保证不会重复例如身份证号用作索引时,可设置为UNIQUE。

2、FULLTEXT: 全文索引

​ 表示全文搜索,在检索长文本的时候,效果最好,短文本建议使用普通索引,但是在检索的时候数据量比较大的时候,现将数据放入一个没有全局索引的表中,然后在用Create Index创建的Full Text索引,要比先为一张表建立Full Text然后在写入数据要快的很多。FULLTEXT 用于搜索很长一篇文章的时候,效果最好。用在比较短的文本,如果就一两行字的,普通的 INDEX 也可以。

3、SPATIAL: 空间索引

​ 空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。
MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建。如果没有指定索引约束,此时创建的索引就是普通索引。而一般情况下只需要创建普通索引。

4、普通索引:如果没有指定索引约束,此时创建的索引就是普通索引。而一般情况下只需要创建普通索引。

10、常见的索引类型有哪些?(高频)

索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型的。

MySQL目前提供了以下4种索引:

  • BTREE索引: 最常见的索引类型,大部分索引都支持 B 树索引。
  • HASH索引:只有Memory引擎支持 , 使用场景简单 。
  • R-tree索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。
  • Full-text (全文索引) :全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。

支持各种存储引擎的索引:

[En]

Support for indexes by various storage engines:

索引 InnoDB引擎 MyISAM引擎 Memory引擎 BTREE索引 支持 支持 支持 HASH 索引 不支持 不支持 支持 R-tree 索引 不支持 支持 不支持 Full-text 5.6版本之后支持 支持 不支持

我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。

11、怎么看到为表格定义的所有索引?

语法:

show index  from  table_name;

示例:查看tb_sku表中的索引信息;

show index from tb_sku ;

Java面试题(二)--MySQL
注意:主键自动创建索引

12、唯一索引比普通索引快吗, 为什么?

唯一索引不一定比普通索引快,而且可能更慢。

[En]

A unique index is not necessarily faster than a normal index, and may be slower.

1、 查询时, 在未使用 limit 1 的情况下, 在匹配到一条数据后, 唯一索引即返回, 普通索引会继续匹配下一条数据, 发现不匹配后返回. 如此看来唯一索引少了一次匹配, 但实际上这个消耗微乎其微。

2、 更新时, 这个情况就比较复杂了. 普通索引将记录放到 change buffer 中语句就执行完毕了。而对唯一索引而言, 它必须要校验唯一性, 因此, 必须将数据页读入内存确定没有冲突, 然后才能继续操作。

对于写多读少的情况 , 普通索引利用 change buffer 有效减少了对磁盘的访问次数, 因此普通索引性能要高于唯一索引.

13、索引的优缺点?

1、优点

  • 提高数据检索的效率,降低数据库的 IO 成本。
  • 通过索引列对数据进行排序,降低数据排序的成本,降低了 CPU 的消耗。

2、缺点

  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 INSERT、UPDATE 和DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
  • 实际上,索引也是表,存放主键和索引字段,指向实体表的记录,因此索引列也会占用空间。
    [En]

    in fact, an index is also a table, which holds the primary key and index fields and points to the records of the entity table, so the index column also takes up space.*

14、什么情况下设置了索引但无法使用?(高频)

环境准备

建表语句:

create table tb_seller (
    sellerid varchar (100),
    name varchar (100),
    nickname varchar (50),
    password varchar (60),
    status varchar (1),
    address varchar (100),
    createtime datetime,
    primary key(sellerid)
)engine=innodb default charset=utf8mb4;

初始化数据sql:

insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('huawei','华为科技有限公司','华为小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('itcast','传智播客教育科技有限公司','传智播客','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('itheima','黑马程序员','黑马程序员','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('luoji','罗技科技有限公司','罗技小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('oppo','OPPO科技有限公司','OPPO官方旗舰店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('ourpalm','掌趣科技股份有限公司','掌趣小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('qiandu','千度科技','千度小店','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('sina','新浪科技有限公司','新浪官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('xiaomi','小米科技','小米官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into tb_seller (sellerid, name, nickname, password, status, address, createtime) values('yijia','宜家家居','宜家家居旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');

创建索引:

create index idx_seller_name_sta_addr on tb_seller(name,status,address);

全时匹配查询:为索引中的所有列指定特定值。在这种情况下,索引生效,执行效率高。

[En]

Full-time matching query: specify specific values for all columns in the index. In this case, the index takes effect and the execution efficiency is high.

explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';

Java面试题(二)--MySQL

违背了最左前缀法则

如果为多列编制索引,请遵循最左侧的前缀规则。表示查询从索引最左侧的前一列开始,不跳过索引中的列。

[En]

If you index multiple columns, follow the leftmost prefix rule. * means that the query starts at the leftmost front column of the index and does not skip the columns in the index. *

匹配最左边的前缀规则并转到索引:

[En]

Match the leftmost prefix rule and go to the index:

Java面试题(二)--MySQL

违法最左前缀法则 , 索引失效:
![[MySQL面试题.png]]

如果满足最左边的规则,但列中发生跳转,则只有最左边的列索引生效:

[En]

If the leftmost rule is met, but a jump occurs in a column, only the leftmost column index takes effect:

Java面试题(二)--MySQL

② 范围查询: 范围查询右边的列,不能使用索引

Java面试题(二)--MySQL
根据前面的两个字段name , status 查询是走索引的, 但是最后一个条件address 没有用到索引。
>= 不走索引
> 走索引

③ 列运算: 不要在索引列上进行运算操作, 索引将失效。

Java面试题(二)--MySQL

④ 字符串: 字符串不加单引号,造成索引失效。

Java面试题(二)--MySQL
由于,在查询时没有对字符串加单引号,MySQL的查询优化器,会自动的进行类型转换,造成索引失效。

⑤ 模糊查询: 以%开头的like模糊查询,索引失效。如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。

Java面试题(二)--MySQL
解决方案 :

通过覆盖索引来解决

Java面试题(二)--MySQL

15、在建立索引的时候,都有哪些需要考虑的因素呢?

① 建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合。

② 如果需要建立联合索引的话,还需要考虑联合索引中的顺序。

③ 此外也要考虑其他方面,比如防止过多的索引对表造成太大的压力

16、创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

MySQL提供了 explain命令来查看语句的执行计划,MySQL在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,也就是执行计划,其中包含了许多信息. 可以通过其中和索引有关的信息来分析是否命中了索引,例如possilbe_key,key,key_len等字段,分别说明了此语句可能会使用的索引,实际使用的索引以及使用的索引长度.

3 SQL优化

17、关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?(高频)

在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。

优化慢查询的第一件事是找出慢查询的原因是什么。

[En]

The first thing to optimize slow queries is to figure out what are the reasons for slow queries.

① 是查询条件没有命中索引?

② 是load了不需要的数据列?

③ 还是数据量太大?

所以优化也是针对这三个方向的:

[En]

So the optimization is also aimed at these three directions:

1、分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。

2、分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。

3、如果是表中的数据量是否太大导致查询慢,可以进行横向或者纵向的分表.

MySQL的 慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过 long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10S以上的语句。默认情况下,Mysql数据库并不启动慢查询日志,需要我们手动来设置这个参数,当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件,也支持将日志记录写入数据库表。

慢查询的配置:

是否开启慢查询日志,1表示开启,0表示关闭
slow_query_log=1

旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log
log_slow_queries=/var/lib/mysql/mysql_slow.log

新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log
slow_query_log_file=/var/lib/mysql/mysql_slow.log

查询阈值慢,当查询时间大于设定的阈值时,进行日志记录。<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Slow query threshold, when the query time is greater than the set threshold, log.</font>*</details>
long_query_time = 1

不使用索引的查询也记录在慢查询日志中(可选)。<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Queries that do not use indexes are also recorded in the slow query log (optional).</font>*</details>
log_queries_not_using_indexes=0

日志存储方式。log_output='FILE'表示将日志存入文件,默认值是'FILE'。log_output='TABLE'表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中。MySQL数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:log_output='FILE,TABLE'。日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件。
log_output='FILE,TABLE'

添加上面配置的重启服务,生成慢查询日志:

[En]

Add the restart service configured above to generate a slow query log:

Java面试题(二)--MySQL
慢查询日志文件内容:
Java面试题(二)--MySQL
执行如下sql语句模拟慢查询:
-- 不会记录到慢查询日志中
select sleep(0.2) ;

-- 会记录到慢查询日志中
select sleep(2) ;

Java面试题(二)--MySQL

18、如何优化SQL?(高频)

SQL语句中IN包含的值不应过多

MySQL对于IN做了相应的优化,即将IN中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也是比较大的。再例如:

select id from table_name where numin(1,2,3) 对于连续的数值,能用between 就不要用in了。

SELECT语句务必指明字段名称

SELECT *增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前断也需要更新。所以要求直接在select后面接上字段名。

如果排序字段没有用到索引,就尽量少排序

如果限制条件中其他字段没有索引,尽量少用or

or两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 union all 或者是union(必要的时候)的方式来代替”or”会得到更好的效果

or查询:

(1) or两边放联合索引,不触发索引(如果两边是单列索引另算)

Java面试题(二)--MySQL

(2) or两边是单列索引,查询走索引

Java面试题(二)--MySQL

(3) or两边只要有一个不是索引就不启用索引查询

单例索引演示:

Java面试题(二)--MySQL
复合索引演示:
Java面试题(二)--MySQL
(4) or两边一个是联合索引的最左索引一个是单例索引才生效,否则失效

示例:

-- 创建单列索引
 create index idx_nickname on tb_seller(nickname) ;

使用索引:
![[MySQL面试题-1.png]]
索引失效:

Java面试题(二)--MySQL
不建议使用%前缀模糊查询:例如LIKE “%name”或者LIKE “%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE”name%”。

19、超大分页怎么处理?(高频)

一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是 limit 1000000 , 10,此时需要MySQL排序前1000010 记

录,仅仅返回1000000 – 1000010 的记录,其他记录丢弃,查询排序的代价非常大 。

示例:

explain select * from tb_sku limit 1000000 , 10 ;

Java面试题(二)--MySQL
执行查询耗时:
Java面试题(二)--MySQL

优化思路一: 在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。

示例:

explain select * from tb_sku s , (select id from tb_sku order by id limit 1000000 , 10 ) t where t.id = s.id ;

Java面试题(二)--MySQL
执行查询耗时:
Java面试题(二)--MySQL
优化思路二: 该方案适用于主键自增的表,可以把limit 查询转换成某个位置的查询 。

示例:

 explain select * from tb_sku where id > 1000000 limit 10 ;

Java面试题(二)--MySQL
执行查询耗时:
Java面试题(二)--MySQL

20、MySQL数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?

1、设计良好的数据库结构, 允许部分数据冗余, 尽量避免join查询, 提高效率。

2、选择合适的表字段数据类型和存储引擎, 适当的添加索引。

3、MySQL 库主从读写分离。

4、找规律分表, 减少单表中的数据量 ,提高查询速度。

5、添加缓存机制, 比如 memcached, redis等。

6、不经常改动的页面, 生成静态页面。

7、书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE。

4 事务

21、什么是事务?(高频)

摘要:由多个操作组成的逻辑单元,组成该逻辑单元的多个操作要么成功,要么失败。

[En]

Summary: a logical unit consisting of multiple operations, and the multiple operations that make up the logical unit either succeed or fail.

举例:转账

22、ACID是什么?可以详细说一下吗?(高频)

A=Atomicity原子性:就是上面说的,要么全部成功,要么全部失败,不可能只执行一部分操作。

C=Consistency一致性:系统(数据库)总是从一个一致性的状态转移到另一个一致性的状态,不会存在中间状态。

I=Isolation隔离性: 通常来说:一个事务在完全提交之前,对其他事务是不可见的.注意前面的通常来说加了红色,意味着有例外情况。

D=Durability持久性:一旦事务提交,那么就永远是这样子了,哪怕系统崩溃也不会影响到这个事务的结果。

23、并发事务带来哪些问题?(高频)

在典型的应用程序中,多个事务并发运行,并且经常操作相同的数据以完成各自的任务(多个用户操作相同的数据)。虽然并发是必要的,但它可能会导致以下问题。

[En]

In a typical application, multiple transactions run concurrently and often manipulate the same data to complete their respective tasks (multiple users operate on the same data). Although concurrency is necessary, it can cause the following problems.

脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是”脏数据”,依据”脏数据”所做的操作可能是不正确的。

丢失修改(Lost to modify):指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

不可重复读(Unrepeatableread):指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

幻读(Phantom read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

24、怎么解决这些问题呢?MySQL的默认隔离级别是?(高频)

解决方案:隔离事务

[En]

Solution: isolate transactions

MySQL的四种隔离级别如下:

未提交读(READ UNCOMMITTED):这个隔离级别下,其他事务可以看到本事务没有提交的部分修改。因此会造成脏读的问题(读取到了其他事务未提交的部分,而之后该事务进行了回滚)。这个级别的性能没有足够大的优势,但是又有很多的问题,因此很少使用.

sql演示:

插入数据
insert into goods_innodb(name) values('华为');
insert into goods_innodb(name) values('小米');

会话一
set session transaction isolation level read uncommitted ;      # 设置事务的隔离级别为read uncommitted
start transaction ;                                             # 开启事务
select * from goods_innodb ;                                    # 查询数据

会话二
set session transaction isolation level read uncommitted ;      # 设置事务的隔离级别为read uncommitted
start transaction ;                                             # 开启事务
update goods_innodb set name = '中兴' where id = 10 ;            # 修改数据

会话一
select * from goods_innodb ;                                    # 查询数据

已提交读(READ COMMITTED):其他事务只能读取到本事务已经提交的部分。这个隔离级别有不可重复读的问题,在同一个事务内的两次读取,拿到的结果竟然不一样,因为另外一个事务对数据进行了修改。

sql演示:

会话一
set session transaction isolation level read committed ;        # 设置事务的隔离级别为read committed
start transaction ;                                             # 开启事务
select * from goods_innodb ;                                    # 查询数据

会话二
set session transaction isolation level read committed ;        # 设置事务的隔离级别为read committed
start transaction ;                                             # 开启事务
update goods_innodb set name = '中兴' where id = 1 ;             # 修改数据

会话一
select * from goods_innodb ;                                    # 查询数据

会话二
commit;                                                         # 提交事务

会话一
select * from goods_innodb ;                                    # 查询数据

REPEATABLE READ(可重复读):可重复读隔离级别解决了上面不可重复读的问题(看名字也知道),但是不能完全解决幻读。MySql默认的事务隔离级别就是:

REPEATABLE READ

select @@tx_isolation;

Java面试题(二)--MySQL

sql演示(解决不可重复读):

会话一
start transaction ;                                             # 开启事务
select * from goods_innodb ;                                    # 查询数据

会话二
start transaction ;                                             # 开启事务
update goods_innodb set name = '荣耀' where id = 1 ;             # 修改数据

会话一
select * from goods_innodb ;                                    # 查询数据

会话二
commit;                                                         # 提交事务

会话一
select * from goods_innodb ;                                    # 查询数据

sql演示(测试不会出现幻读的情况):

会话一
start transaction ;                                             # 开启事务
select * from goods_innodb ;                                    # 查询数据

会话二
start transaction ;                                             # 开启事务
insert into goods_innodb(name) values('小米');                   # 插入数据
commit;                                                         # 提交事务

会话一
select * from goods_innodb ;                                    # 查询数据

sql演示(测试出现幻读的情况):

表结构进行修改
ALTER TABLE goods_innodb ADD version int(10) NULL ;

会话一
start transaction ;                                             # 开启事务
select * from goods_innodb where version = 1;                   # 查询一条不满足条件的数据

会话二
start transaction ;                                             # 开启事务
insert into goods_innodb(name, version) values('vivo', 1);      # 插入一条满足条件的数据
commit;                                                         # 提交事务

会话一
update goods_innodb set name = '金立' where version = 1;         # 将version为1的数据更改为'金立'
select * from goods_innodb where version = 1;                   # 查询一条不满足条件的数据

SERIALIZABLE(可串行化):这是最高的隔离级别,可以解决上面提到的所有问题,因为他强制将所以的操作串行执行,这会导致并发性能极速下降,因此也不是很常用。

5 锁

25、MySQL中有哪几种锁?

从对数据操作的粒度分 :

1) 表锁:操作时,会锁定整个表。

2) 行锁:操作时,会锁定当前操作行。

3) 页面锁:会锁定一部分的数据

从对数据操作的类型分:

1) 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。

2) 写锁(排它锁):当前操作没有完成之前,它会阻断其他写锁和读锁。

对每个存储引擎的锁定支持:

[En]

Lock support for each storage engine:

存储引擎 表级锁 行级锁 页面锁 MyISAM 支持 不支持 不支持 InnoDB 支持 支持 不支持 MEMORY 支持 不支持 不支持 BDB 支持 不支持 支持

MySQL这2种锁的特性可大致归纳如下 :

锁类型 特点 表级锁 偏向MyISAM 存储引擎,开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁 偏向InnoDB 存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 页面锁 开销和加锁时间界于表锁和行锁之间; 会出现死锁; 锁定粒度界于表锁和行锁之间, 并发度一般。

从锁的角度来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web 应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并查询的应用,如一些在线事务处理(OLTP)系统。

MyISAM 在执行查询语句(SELECT)前,会自动给涉及的表 加读锁,在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表 加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用 LOCK TABLE 命令给 MyISAM 表显式加锁。

显示加表锁语法:

加读锁 : lock table table_name read;
加写锁 : lock table table_name write;
解锁:     unlock tables;

InnoDB 的行锁模式

InnoDB 实现了以下两种类型的行锁。

  • 共享锁(S):又称为读锁,简称S锁,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
  • 排他锁(X):又称为写锁,简称X锁,排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集(行)加 排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;

可以通过以下语句向记录集添加共享锁或排他锁。

[En]

You can add a shared lock or an exclusive lock to the recordset through the following statement.

共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X) :SELECT * FROM table_name WHERE ... FOR UPDATE

Original: https://www.cnblogs.com/xy1857/p/16444398.html
Author: Orator-xy
Title: Java面试题(二)–MySQL

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/505258/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • JUC自定义线程池练习

    JUC自定义线程池练习 首先上面该线程池的大致流程 自定义阻塞队列 首先定义一个双向的队列和锁一定两个等待的condition 本类用lock来控制多线程下的流程执行 take和p…

    数据库 2023年6月11日
    0141
  • 翻译|使用 StatefulSet 运行数据库应用

    本文介绍 Kubernetes 支持数据库等有状态应用的常见解决方案:StatefulSet。 我们在构建机器学习向量管理时面临的一个重要问题是:如何持久化数据,避免数据丢失? […

    数据库 2023年5月24日
    0171
  • 标识多个物体并返回物体中心坐标方法的实现

    概述 在图像处理时,可能不可避免的需要计算图像中目标体的中心点,因而本片文章重点讲如何用传统图像处理方式来计算图像中目标体的中心。 方案 刚开始在考虑这个问题时其实也考虑了很多方法…

    数据库 2023年6月11日
    0157
  • MySQL学习笔记

    MySQL学习笔记 解决MYSQL中文乱码问题 一、乱码的原因: 1、 client客户端的编码不是utf8 2、server端的编码不是utf8 3、database数据库的编码…

    数据库 2023年6月14日
    0146
  • MySQL45讲之备库并行复制策略

    前言 本文主要介绍 MySQL 备库的并行复制策略。 为什么备库需要并行复制 如果主数据库有大量的更新操作,因为主数据库可以并发写入,而从数据库只能在单个线程中执行,那么从数据库的…

    数据库 2023年5月24日
    0143
  • Java并发编程之CAS

    在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大手段。其中 Lock 是 JDK 层面的锁机制,是轻量级锁,底层使…

    数据库 2023年6月11日
    0119
  • 毫秒级!千万人脸库快速比对,上亿商品图片检索,背后的极速检索用了什么神器? ⛵

    💡 作者:韩信子@ShowMeAI📘 机器学习实战系列:https://www.showmeai.tech/tutorials/41📘 深度学习实战系列:https://www.s…

    数据库 2023年6月14日
    0132
  • MyBatis + SpringMVC 总结

    创建 MyBatis 的主配置文件(mybatis-config.xml):环境,事务管理,数据源 给类取别名 配置支持懒加载 创建接口以及接口的映射文件(UserMapper,U…

    数据库 2023年6月11日
    0155
  • 自定义 systemd service

    Red Hat Linux 自 7 版本后 采用systemd 形式取代原先 init ,用户可以参考 系统service 创建自己的service ,以便于日常统一管理,系统se…

    数据库 2023年6月15日
    0143
  • 一,Flink快速上手

    1.依赖配置 1.1 pom文件 8 8 1.13.0 1.8 2.12 1.7.30 org.apache.flink flink-java ${flink.version} o…

    数据库 2023年6月6日
    0140
  • django中的视图层

    1.什么是视图层 简单来说,就是用来接收路由层传来的请求,从而做出相应的响应返回给浏览器 2.视图层的格式与参数说明 2.1基本格式 from django.http import…

    数据库 2023年6月14日
    0123
  • redhat 7.4从openssh7.6离线升级openssh8.4p1解决方法

    具体需求 这几天生产环境服务器又进行了安全扫描,每次都会报一下漏洞错误。虽然只有一个高危问题,但是每次看到ssh远程漏洞都很烧脑 “主要是里面坑太多了”,闲…

    数据库 2023年6月14日
    0116
  • 记录一次docker镜像拉取失败的问题

    syslog日志 Mar 13 08:42:41 xxx dockerd[30691]: time=”2022-03-13T08:42:41.928436506Z&#8…

    数据库 2023年6月9日
    0185
  • Java关键字总结(一)

    static总结: 1、修饰静态变量,通过类名.变量名,不需要实例化对象,属于静态资源,所有类实例共享 2、修饰静态方法,通过类名.方法,不需要实例化对象,属于静态资源,所有类实例…

    数据库 2023年6月6日
    0170
  • 2022-8-29 javaweb 第一天 servlet/tomcat

    软件架构 1、C/S架构:客户端 / 服务器——–QQ,Typora,腾讯会议。 2、B/S架构:浏览器 / 服务器——…

    数据库 2023年6月14日
    0146
  • 我的JAVA面试题备忘录

    以下是我收集的一些问题,有的是网上摘录的,有的是自己参加面试被问到的,有的是工作或学习时遇到的,等等。 为什么要记录这些呢? 一方面,我相信,这样做对我自己的技术提升是有帮助的。在…

    数据库 2023年6月6日
    0101
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球