文链接:https://mp.weixin.qq.com/s/2Vu1DDJKUu79Ns5YK-VFaQ
分享一道群友面试虾皮遇到的 MySQL 面试真题。原面试题如下:
昨天抽了一晚上对这些问题进行了解答,希望对准备面试以及 MySQL 复习知识点的小伙伴有帮助。
马上秋招就来了,最近一直在抽时间更新面试真题(原创不易,有帮助的话,点赞分享就是对 Guide 最大的鼓励):
MySQL 核心在于存储引擎,想要深入学习 MySQL,必定要深入研究 MySQL 存储引擎。
MySQL 支持多种存储引擎,你可以通过 show engines 命令来查看 MySQL 支持的所有存储引擎。
查看 MySQL 提供的所有存储引擎
从上图我们可以查看出, MySQL 当前默认的存储引擎是 InnoDB。并且,所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
我这里使用的 MySQL 版本是 8.x,不同的 MySQL 版本之间可能会有差别。
MySQL 5.5.5 之前,MyISAM 是 MySQL 的默认存储引擎。5.5.5 版本之后,InnoDB 是 MySQL 的默认存储引擎。
你可以通过 select version() 命令查看你的 MySQL 版本。
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27 |
+-----------+
1 row in set (0.00 sec)
你也可以通过 show variables like '%storage_engine%' 命令直接查看 MySQL 当前默认的存储引擎。
查看 MySQL 当前默认的存储引擎
如果你只想查看数据库中某个表使用的存储引擎的话,可以使用 show table status from db_name where name='table_name'命令。
查看表的存储引擎
如果你想要深入了解每个存储引擎以及它们之间的区别,推荐你去阅读以下 MySQL 官方文档对应的介绍(面试不会问这么细,了解即可):
MySQL 存储引擎采用的是插件式架构,支持多种存储引擎,我们甚至可以为不同的数据库表设置不同的存储引擎以适应不同场景的需要。存储引擎是基于表的,而不是数据库。
并且,你还可以根据 MySQL 定义的存储引擎实现标准接口来编写一个属于自己的存储引擎。这些非官方提供的存储引擎可以称为第三方存储引擎,区别于官方存储引擎。像目前最常用的 InnoDB 其实刚开始就是一个第三方存储引擎,后面由于过于优秀,其被 Oracle 直接收购了。
MySQL 官方文档也有介绍到如何编写一个自定义存储引擎,地址:https://dev.mysql.com/doc/internals/en/custom-engine.html 。
MySQL 5.5 之前,MyISAM 引擎是 MySQL 的默认存储引擎,可谓是风光一时。
虽然,MyISAM 的性能还行,各种特性也还不错(比如全文索引、压缩、空间函数等)。但是,MyISAM 不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。
MySQL 5.5.5 之前,MyISAM 是 MySQL 的默认存储引擎。5.5.5 版本之后,InnoDB 是 MySQL 的默认存储引擎。
言归正传!咱们下面还是来简单对比一下两者:
1.是否支持行级锁
MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。
也就说,MyISAM 一锁就是锁住了整张表,这在并发写的情况下是多么滴憨憨啊!这也是为什么 InnoDB 在并发写的时候,性能更牛皮了!
2.是否支持事务
MyISAM 不提供事务支持。
InnoDB 提供事务支持,实现了 SQL 标准定义了四个隔离级别,具有提交(commit)和回滚(rollback)事务的能力。并且,InnoDB 默认使用的 REPEATABLE-READ(可重读)隔离级别是可以解决幻读问题发生的(基于 MVCC 和 Next-Key Lock)。
关于 MySQL 事务的详细介绍,可以看看我写的这篇文章:MySQL 事务隔离级别详解[1]。
3.是否支持外键
MyISAM 不支持,而 InnoDB 支持。
外键对于维护数据一致性非常有帮助,但是对性能有一定的损耗。因此,通常情况下,我们是不建议在实际生产项目中使用外键的,在业务代码中进行约束即可!
阿里的《Java 开发手册》也是明确规定禁止使用外键的。
不过,在代码中进行约束的话,对程序员的能力要求更高,具体是否要采用外键还是要根据你的项目实际情况而定。
总结:一般我们也是不建议在数据库层面使用外键的,应用层面可以解决。不过,这样会对数据的一致性造成威胁。具体要不要使用外键还是要根据你的项目来决定。
4.是否支持数据库异常崩溃后的安全恢复
MyISAM 不支持,而 InnoDB 支持。
使用 InnoDB 的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log 。
5.是否支持 MVCC
MyISAM 不支持,而 InnoDB 支持。
讲真,这个对比有点废话,毕竟 MyISAM 连行级锁都不支持。MVCC 可以看作是行级锁的一个升级,可以有效减少加锁操作,提高性能。
6.索引实现不一样。
虽然 MyISAM 引擎和 InnoDB 引擎都是使用 B+Tree 作为索引结构,但是两者的实现方式不太一样。
InnoDB 引擎中,其数据文件本身就是索引文件。相比 MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按 B+Tree 组织的一个索引结构,树的叶节点 data 域保存了完整的数据记录。
详细区别,推荐你看看我写的这篇文章:MySQL 索引详解[2]。
大多数时候我们使用的都是 InnoDB 存储引擎,在某些读密集的情况下,使用 MyISAM 也是合适的。不过,前提是你的项目不介意 MyISAM 不支持事务、崩溃恢复等缺点(可是~我们一般都会介意啊!)。
《MySQL 高性能》上面有一句话这样写到:
不要轻易相信“MyISAM 比 InnoDB 快”之类的经验之谈,这个结论往往不是绝对的。在很多我们已知场景中,InnoDB 的速度都可以让 MyISAM 望尘莫及,尤其是用到了聚簇索引,或者需要访问的数据都可以放入内存的应用。
一般情况下我们选择 InnoDB 都是没有问题的,但是某些情况下你并不在乎可扩展能力和并发能力,也不需要事务支持,也不在乎崩溃后的安全恢复问题的话,选择 MyISAM 也是一个不错的选择。但是一般情况下,我们都是需要考虑到这些问题的。
因此,对于咱们日常开发的业务系统来说,你几乎找不到什么理由再使用 MyISAM 作为自己的 MySQL 数据库的存储引擎。
言
本篇文章主要介绍了前端HTML5几种存储方式的总结 ,主要包括本地存储localstorage,本地存储sessionstorage,离线缓存(application cache),Web SQL,IndexedDB。有兴趣的可以了解一下。
正文开始~
h5之前,存储主要是用cookies。cookies缺点有在请求头上带着数据,大小是4k之内。主Domain污染。
主要应用:购物车、客户登录
对于IE浏览器有UserData,大小是64k,只有IE浏览器支持。
目标
存储方式:
以键值对(Key-Value)的方式存储,永久存储,永不失效,除非手动删除。
大小:
每个域名5M
支持情况:
注意:IE9 localStorage不支持本地文件,需要将项目署到服务器,才可以支持!
if(window.localStorage){ alert('This browser supports localStorage'); }else{ alert('This browser does NOT support localStorage'); }
常用的API:
getItem //取记录
setIten//设置记录
removeItem//移除记录
key//取key所对应的值
clear//清除记录
存储的内容:
数组,图片,json,样式,脚本。。。(只要是能序列化成字符串的内容都可以存储)
HTML5 的本地存储 API 中的 localStorage 与 sessionStorage 在使用方法上是相同的,区别在于 sessionStorage 在关闭页面后即被清空,而 localStorage 则会一直保存。
本地缓存应用所需的文件
使用方法:
①配置manifest文件
页面上:
<!DOCTYPE HTML> <html manifest="demo.appcache"> ... </html>
Manifest 文件:
manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。
manifest 文件可分为三个部分:
①CACHE MANIFEST - 在此标题下列出的文件将在首次下载后进行缓存
②NETWORK - 在此标题下列出的文件需要与服务器的连接,且不会被缓存
③FALLBACK - 在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面)
完整demo:
CACHE MANIFEST # 2016-07-24 v1.0.0 /theme.css /main.js NETWORK: login.jsp FALLBACK: /html/ /offline.html
服务器上:manifest文件需要配置正确的MIME-type,即 "text/cache-manifest"。
如Tomcat:
<mime-mapping> <extension>manifest</extension> <mime-type>text/cache-manifest</mime-type> </mime-mapping>
常用API:
核心是applicationCache对象,有个status属性,表示应用缓存的当前状态:
0(UNCACHED) : 无缓存, 即没有与页面相关的应用缓存
1(IDLE) : 闲置,即应用缓存未得到更新
2 (CHECKING) : 检查中,即正在下载描述文件并检查更新
3 (DOWNLOADING) : 下载中,即应用缓存正在下载描述文件中指定的资源
4 (UPDATEREADY) : 更新完成,所有资源都已下载完毕
5 (IDLE) : 废弃,即应用缓存的描述文件已经不存在了,因此页面无法再访问应用缓存
相关的事件:
表示应用缓存状态的改变:
checking : 在浏览器为应用缓存查找更新时触发
error : 在检查更新或下载资源期间发送错误时触发
noupdate : 在检查描述文件发现文件无变化时触发
downloading : 在开始下载应用缓存资源时触发
progress:在文件下载应用缓存的过程中持续不断地下载地触发
updateready : 在页面新的应用缓存下载完毕触发
cached : 在应用缓存完整可用时触发
Application Cache的三个优势:
① 离线浏览
② 提升页面载入速度
③ 降低服务器压力
注意事项:
1. 浏览器对缓存数据的容量限制可能不太一样(某些浏览器设置的限制是每个站点 5MB)
2. 如果manifest文件,或者内部列举的某一个文件不能正常下载,整个更新过程将视为失败,浏览器继续全部使用老的缓存
3. 引用manifest的html必须与manifest文件同源,在同一个域下
4. 浏览器会自动缓存引用manifest文件的HTML文件,这就导致如果改了HTML内容,也需要更新版本才能做到更新。
5. manifest文件中CACHE则与NETWORK,FALLBACK的位置顺序没有关系,如果是隐式声明需要在最前面
6. FALLBACK中的资源必须和manifest文件同源
7. 更新完版本后,必须刷新一次才会启动新版本(会出现重刷一次页面的情况),需要添加监听版本事件。
8. 站点中的其他页面即使没有设置manifest属性,请求的资源如果在缓存中也从缓存中访问
9. 当manifest文件发生改变时,资源请求本身也会触发更新
离线缓存与传统浏览器缓存区别:
1. 离线缓存是针对整个应用,浏览器缓存是单个文件
2. 离线缓存断网了还是可以打开页面,浏览器缓存不行
3. 离线缓存可以主动通知浏览器更新资源
关系数据库,通过SQL语句访问
Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 APIs。
支持情况:
Web SQL 数据库可以在最新版的 Safari, Chrome 和 Opera 浏览器中工作。
核心方法:
①openDatabase:这个方法使用现有的数据库或者新建的数据库创建一个数据库对象。
②transaction:这个方法让我们能够控制一个事务,以及基于这种情况执行提交或者回滚。
③executeSql:这个方法用于执行实际的 SQL 查询。
打开数据库:
var db=openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024,fn); //openDatabase() 方法对应的五个参数分别为:数据库名称、版本号、描述文本、数据库大小、创建回调
执行查询操作:
var db=openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS WIN (id unique, name)'); });
插入数据:
var db=openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS WIN (id unique, name)'); tx.executeSql('INSERT INTO WIN (id, name) VALUES (1, "winty")'); tx.executeSql('INSERT INTO WIN (id, name) VALUES (2, "LuckyWinty")'); });
读取数据:
db.transaction(function (tx) { tx.executeSql('SELECT * FROM WIN', [], function (tx, results) { var len=results.rows.length, i; msg="<p>查询记录条数: " + len + "</p>"; document.querySelector('#status').innerHTML +=msg; for (i=0; i < len; i++){ alert(results.rows.item(i).name ); } }, null); });
由这些操作可以看出,基本上都是用SQL语句进行数据库的相关操作,如果你会MySQL的话,这个应该比较容易用。
索引数据库 (IndexedDB) API(作为 HTML5 的一部分)对创建具有丰富本地存储数据的数据密集型的离线 HTML5 Web 应用程序很有用。同时它还有助于本地缓存数据,使传统在线 Web 应用程序(比如移动 Web 应用程序)能够更快地运行和响应。
异步API:
在IndexedDB大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求——响应的模式,比如打开数据库的操作
这样,我们打开数据库的时候,实质上返回了一个DB对象,而这个对象就在result中。由上图可以看出,除了result之外。还有几个重要的属性就是onerror、onsuccess、onupgradeneeded(我们请求打开的数据库的版本号和已经存在的数据库版本号不一致的时候调用)。这就类似于我们的ajax请求那样。我们发起了这个请求之后并不能确定它什么时候才请求成功,所以需要在回调中处理一些逻辑。
关闭与删除:
function closeDB(db){ db.close(); } function deleteDB(name){ indexedDB.deleteDatabase(name); }
数据存储:
indexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。
我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异。
学习从来不是一个人的事情,要有个相互监督的伙伴,想要学习或交流前端问题的小伙伴可以私信“学习”小明获取web前端入门资料,一起学习,一起成长!
骨文公司宣布在 MySQL 中将引入对 JavaScript 的支持,这一消息在前端、后端技术圈引起了广泛关注。本文首先阐述MySQL 中将引入对 JavaScript 的支持的背景及应用实践,最后从前端视角来分析这一变化会给前端开发人员带来哪些利好。
MySQL 不断进行创新,现在数据库中包含了丰富的程序编程功能。开发人员现在可以在 MySQL 数据库服务器中编写 JavaScript 存储程序(函数和过程)。这些存储程序将通过 GraalVM 运行时间运行。该功能在 MySQL 企业版中作为预览版提供,可通过 Oracle Technology Network (OTN) 下载。MySQL-JavaScript 还可在 OCI、AWS 和 Azure 上的 MySQL Heatwave 云服务中使用。
JavaScript 是最受开发人员欢迎的编程语言。除了更简单的语法和对现代语言功能的支持外,其受欢迎的一个关键因素是丰富的生态系统提供了大量可重复使用的代码模块。
当需要持久存储时,最流行的开源数据库 MySQL 将是 JavaScript 开发人员的自然选择。通过在存储程序中支持 JavaScript,开发人员将能用熟悉的语言编写 MySQL 存储程序,并利用广泛的 JavaScript 生态系统!
对 JavaScript 存储程序的支持,不仅可以利用庞大的生态系统提高开发人员的工作效率,还能让更多开发人员掌握编写存储程序的必要技能。换句话说,企业现在可以利用广泛可用的 JavaScript 技能集进行后端开发,从而发掘更多的开发人才。
存储程序的一个关键优势是最大限度地减少了数据库服务器和应用程序之间的数据移动。出于多种原因,传输大量数据(尤其是批处理数据)可能会造成很多问题:
使用存储程序在数据库内处理数据是解决这些问题的常用方法。
MySQL-JavaScript 为应用程序设计带来了新的机遇,而这些机遇曾一度受限于权衡利弊。JavaScript 存储程序使开发人员能够避开数据移动,在数据库内轻松无缝地实现高级数据处理逻辑。下面列出了一些简单的用例:
所提供的示例只是该功能潜力的一个缩影。还有更多复杂的用例,如部署完整的数据管道和为机器学习应用建立暂存环境。
MySQL 正在引入对 JavaScript 存储程序的支持。用户现在可以在数据库中表达丰富的程序逻辑。JavaScript 运行时通过 GraalVM 集成,用户可以免费使用 GraalVM 的所有企业版 (EE) 功能,如编译器优化、性能和安全功能。
该版本支持:
ECMAScript 标准库包括许多基本的使用操作和数据结构,使实现变得简单而富有表现力。开发人员还可以从在线软件包管理器(如 "npm")中重用数百万个可用的第三方软件包。
GraalVM 是 Oracle 的编译器生态系统,包括 JDK 以及 JavaScript、R、Python、Ruby 和 Java 等语言实现。它包括即时(JIT)和超前(AOT)编译技术。它还提供了一个完全托管的虚拟机,具有沙箱功能和工具支持。MySQL-JavaScript 与 GraalVM 企业版集成。
要在 MySQL 中创建 JavaScript 存储程序,可以使用与传统存储函数和存储过程相同的 SQL 语句变体:
CREATE FUNCTION gcd_js (a INT, b INT) RETURNS INT
LANGUAGE JAVASCRIPT AS $$
let [x, y]=[Math.abs(a), Math.abs(b)];
while(y) [x, y]=[y, x % y];
return x;
$$;
从上面的示例可以看出,JavaScript 代码是直接嵌入到 SQL 可调用函数的定义中的。参数的名称可以在 JavaScript 代码中直接引用,当函数被调用时,SQL 类型和 JavaScript 类型之间将进行隐式类型转换。要调用 JavaScript 存储过程,应使用 CALL 语句,这与常规的 SQL 存储过程类似。存储过程支持输入和输出参数。
JavaScript 函数可以在任何可以调用传统 SQL 函数的 SQL 语句中调用,如 SELECT 表达式、WHERE、GROUP BY 和 ORDER BY 子句、DML、DDL、视图等。下面是一个调用我们在上面定义的函数的 SQL 语句示例:
SELECT col1, col2, gcd_js(col1,col2)
FROM my_table
WHERE gcd_js(col1, col2) > 1
ORDER BY gcd_js(col1, col2);
CREATE TABLE gcd_table
AS SELECT gcd_js(col1,col2)
FROM my_table;
调试与软件开发同步进行。当 JavaScript 程序在数据库中运行时,MySQL-JavaScript 功能会提供额外的 SQL 接口,以帮助排除故障。
CREATE PROCEDURE division (IN a INT, IN b INT, OUT result DOUBLE)
LANGUAGE JAVASCRIPT AS $$
function validate(num) {
console.log("validating input value: ", num);
if (num===0) throw ("Division by Zero!");
}
validate(b);
result=a / b;
$$
JavaScript 异常与 MySQL 错误之间的转换是透明的。除标准输出外,开发人员还可以访问 JavaScript 堆栈跟踪。
CALL division( 5, 0, @res);
ERROR 6000 (HY000): JavaScript> Division by Zero!
SELECT mle_session_state("stdout");
validating input value: 0
SELECT mle_session_state("stack_trace");
<js> validate(division:9:187-214)
<js> division(division:11:222-232)
<js> :anonymous(division:15:256-265)
</js></js></js>
MySQL 中的 JavaScript 支持可提供最高级别的安全性、隔离性和数据保护。MySQL 的 JavaScript 依赖于业界公认的 Oracle GraalVM 安全保证。
虚拟机沙盒可确保恶意代码无法入侵 MySQL 服务器的其他模块。每个存储程序都在自己的上下文中解析和执行。这种隔离策略不允许一个存储程序读取或修改其他存储程序的数据或代码。JavaScript 用户代码生成或操作线程受到限制,而且 JavaScript 用户代码无法访问网络通信或文件系统。
JavaScript 存储程序基于标准的 MySQL 权限模型。只有有权限的用户才能创建存储程序。对 SP 的访问也可以通过权限来控制。一个用户可以定义其他用户可以执行的存储程序。
JavaScript 存储程序可与传统的 SQL 存储程序无缝兼容。该功能与存储引擎无关,可以透明地从 InnoDB、Lakehouse 和 HeatWave 访问数据。
MySQL Heatwave 服务现在已在 OCI、AWS 和 Azure 服务部署中预装并配置了 JavaScript。对于 MySQL 企业版,该功能需要手动安装和配置。
MySQL-JavaScript 集成针对其特定用例使用定制的虚拟机,以实现最佳的端到端性能。这种定制基于 GraalVM 的超前(AOT)编译,将语言实现编译成本地二进制表示法,以便快速处理。
GraalVM 拥有自己基于 ECMAScript 2021 标准的 JavaScript 实现。该语言实现在性能方面很有竞争力,尽管它是使用 GraalVM 的 Polyglot 框架实现的,该框架侧重于在同一虚拟机中支持多种编程语言。
最后,MySQL-JavaScript 功能还得益于 GraalVM 企业版的各种先进优化技术,如编译器优化,包括积极的内联和部分转义分析。这还包括一个配置文件引导的即时(JIT)编译器,可在运行时在解释器和本地编译之间切换。
随着全栈开发岗位在国内外的普及,越来越多的开发者开始转变全栈开发人员或者工程师。全栈开发在大部分情况下对前端、后端、运维工程师的工作职责进行了整合,主要包括前端、后端 和 DevOps。在 MySQL 中将引入对 JavaScript 的支持,对于前端或者全栈开发人员来说有以下好处:
MySQL-JavaScript 使开发人员能够直接在 MySQL 服务器中表达复杂的编程逻辑。这样,开发人员就能将应用程序中的数据密集型部分推近数据,从而降低数据移动成本。使用基于 ECMAScript 2021 的 JavaScript 可以防止供应商锁定问题,同时开发人员还可以享受 GraalVM(企业版)的所有优势,而无需支付额外费用。要免费试用 MySQL-JavaScript,请从 Oracle Technology Network (OTN) 下载 MySQL 企业版。MySQL-JavaScript还与MySQL HeatWave云服务无缝集成,开发人员可通过指尖获得最新的创新技术。MySQL向 JavaScript 集成的转变预示着开发人员将获得更多功能和更易用的环境。
*请认真填写需求信息,我们会在24小时内与您取得联系。