故障分析 | 库表名-大小写不规范,运维两行泪

作者:刘聪

爱可生华东交付服务部 DBA 成员,专职 MySQL 故障处理及相关技术支持。座右铭:好好学习,天天向上。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

一、问题描述

客户需要做一套库的迁移,因为库的数据量不大,40G左右,并且需要到远程机器上去做全量恢复。所以第一时间想到的自然是 mysqldump 工具来做。但是没想到会发生这种“惨案”。

mysqldump 备份失败,报错表不存在。

检查 MySQL 客户端去查看表信息以及表的物理文件包括环境信息(是否严格区分大小写),整理的现象如下:

  • mysqldump 报错:table doesn't exist;
  • show tables 观察:db 存在,报错的 table 也存在;
  • select 查看表数据:报错 table doesn't exist ;
  • 观察物理文件:db.opt 文件不存在;报错的 table,idb 文件不存在,仅有 frm 文件;
  • 查看 mysql-error.log :有 DROP database 的提示,且记录了报错 table 的 frm 文件 was lost ;
  • MySQL 环境信息:lower_case_table_names = 1 。

二、分析诊断

首先,我们看一下 MySQL 官网提供的信息(官网链接:https://dev.mysql.com/doc/refman/5.7/en/identifier-case-sensitivity.html)。

根据下面截图信息可以确定 Unix 平台上,lower_case_table_names 默认 = 0 ,是大小写敏感的。

从 mysqldump 报错所提示的表名中包含了大写,不难推断出:是在 lower_case_table_names = 0 条件下,创建了该表,所以表名和物理文件名也都包含大写。而当前的 MySQL 环境是 lower_case_table_names = 1(也就是不论 sql 中是否明确了表名的大小写,均按小写去匹配),可以确定此环境变量有做过变更。

结合 mysql-error.log 的报错信息提示,可能有 DROP database 动作执行过。且数据库目录中的 db.opt 文件缺失这点,更加增强了 DROP database 的可能性。

那么,我们不妨做出如下猜想:

在 lower_case_table_names = 1 环境下,下发了 DROP database 操作。由于操作系统 Linux 是大小写敏感的,MySQL 使用小写字母去匹配需要删除的库表文件,而.frm文件名中包含了大写,无法匹配,导致文件残留(mysql-error.log 此时记录,在删库过程中,无法找到对应.frm文件)。

三、场景模拟

测试环境:

操作系统

CentOS Linux release 7.5.1804 (Core)

MySQL版本

5.7.25, for linux-glibc2.12 (x86_64)

为了证实第二节的猜想是否准确,设计如下实验,模拟复现 mysqldump 报错。

  • 在 lower_case_table_names=0 ,严格区分大小写条件下创建测试库‘test_database’和测试表‘Test_table’;
  • 修改配置文件 lower_case_table_names=1 ,并重启 MySQL ;
  • 在 lower_case_table_names=1 条件下,模拟删除数据库:test_database ;
  • 查看物理文件信息以及 mysql-error.log 信息;
  • 使用 mysqldump 触发备份动作,复现报错。

通过以上实验,可以论证第二节的推测是准确的,并总结如下结论:

  • 操作系统 Linux 是大小写敏感的,在 lower_case_table_names=0(默认值)条件下,库表的物理文件会明确区分大小写;
  • 在 lower_case_table_names=1 条件下,MySQL 使用小写字母(不论 sql 语句里是否明确使用大写表名)去匹配需要删除的库表文件;
  • 在 lower_case_table_names=1 条件下,下发 Drop database 操作,由于表 frm 文件名包含大写,无法匹配,因此残留,而 idb 文件不论大小写都会被删除。

四、报错解决方案

通过第三节的场景模拟可以推测出,应用人员其实本意是要将库下的数据全部删除掉,但是因 MySQL 的环境因素,以及运维人员的操作不当,导致遗留下.frm文件未被清理掉。那么我们可以直接跳过相关库的备份,从而绕过此报错。

五、运维建议

运维中,难免有库表的迁移和改造的需求,这时需要特别注意 lower_case_table_names 的值以及库、表名的大小写,稍不留神就报错库或者表不存在。对此,整理如下两个场景以供大家运维参考。

场景1:将 MySQL 的环境变量 lower_case_table_names 从默认的 0 ,修改为1

  • 先将库名和表名转换为小写;
  • 编辑配置文件,添加配置:lower_case_table_names = 1 ;
  • 重启 MySQL 。

场景2:将大写的表名、库名规范改成小写的:

  • 表名改造:可以直接使用 RENAME TABLE 语句;
  • 库名改造:需要先使用 mysqldump ,将数据全部导出后,重建库名,再将数据导入进去。

致谢:感谢爱可生DBA巨佬操盛春、晏泽的鼎力相助!

本文转载于网络 如有侵权请联系删除

相关文章

  • windows 显示进程的命令 TASKLIST 详解

    大家好,又见面了,我是你们的朋友全栈君。用jstat查看jvm内存的使用的情况时,因为是windows机器,不能使用top命令方便的查出来,进程好在网上搜了一下看到了在windows原来使用的是tasklist特意将tasklist的用法记录下来。“Tasklist”命令是一个用来显示运行在本地或远程计算机上的所有进程的命令行工具,带有多个执行参数。它的使用格式为: TASKLIST[/Ssystem[/Uusername[/P[password]]]] [/M[module]|/SVC|/V][/FIfilter][/FOformat][/NH]参数列表: /Ssystem指定连接到的远程系统(IP)。 /U[domain\]user指定使用哪个用户执行这个命令。 /P[password]为指定的用户指定密码。 /M[module]列出调用指定的DLL模块的所有进程。 如果没有指定模块名,显示每个进程加载的所有模块。 /SVC显示每个进程中的服务。 /V指定要显示详述信息。 /FIfilter显示一系列符合筛选器指定的进程。 /FOformat指定输出格式,有效值:“TABLE”、”

  • 电赛专题 | G题-双路语音同传

    有幸邀请到了在2019大学生电子设计大赛的获奖优秀队员为本公众号投稿,将分几次推文为大家介绍几只优秀队伍的作品。学校:西安电子科技大学作者:步枫施炜洛魏巍指导教师:蔡觉平康海燕摘要:本系统采用频分复用的思想,将两路语音信号调制成不同的频带,从而实现了双路语音同传的功能。使用压控振荡器MAX2605对语音信号进行FM调制、锁相环LMX2571对FM波解调、乘法器AD835和加法器VCA810对双路语音信号进行合成,带通滤波器和AD835对解调信号进行语音分离,完美的完成了题目的各项要求。并且通过对各级电路之间进行合理的级联和阻抗匹配、在电路传输过程中综合应用了去耦电容、滤波、使用屏蔽线传输信号以及使用屏蔽罩等,降低环境噪声对系统中信号传输的影响。在天线发射前接入功率射频放大模块,提高了天线发射接收的距离,降低了噪声对接收信号的影响。此外,我们在发挥其他部分加入双路音乐播放功能和播放广播功能。关键词:双路语音同传频分复用锁相环解调无线模拟信号传输调频广播接收一、系统构成根据该题的各项技术指标要求,双路语音信号的同步传输、对48.5Mhz信号进行FM调制与解调、无线通信系统中载波的抗干扰能力

  • Spark笔记14-SparkStreaming运行及创建

    SparkStreaming数据源SparkStreaming的数据来源广泛,主要有KafkaHDFSFlumeDataBasesDashboardsTcpsocket基本原理将实时输入的数据流以时间片(秒级)为单位进行拆分,然后经过Spark引擎之后,以类似批处理的方式处理每个时间片的数据。用一系列微小的批处理来模拟流计算,并不是真正的流计算 SparkStreaming和StormSSStorm毫秒级响应无法实现可以实现实时计算可以实时计算可以实时计算容错处理RDD数据集更容易、更高效的容错处理高度容错计算方式兼容批量和实时处理数据实时流计算如果需要同时处理实时数据和历史数据,则可以使用SparkStreaming 容错性好可以同时支持实时和历史数据Sparkstreaming运行机制SparkStreaming中有个组件Receiver。长期运行的task跑在一个Executor上每个Receiver负责一个数据源,多种数据来源编写

  • 浅谈小知识

    小编看了本关于移动应用UI设计的书,就把测试需了解的相关知识整理了下,希望能帮助到大家。 1,智能手机的屏幕1)英寸手机屏幕尺寸有3.5英寸,4.3英寸,4.7英寸和5.5英寸。因为手机屏幕使用的玻璃是一整块生产的,然后切割成一块一块,考虑到利用率与成本,获得最优的玻璃切割利用率,避免切割剩余材料的浪费,所以有了以上尺寸。2)像素用放大镜可以看出图像是由一个个小点组成,这些小点就是像素点。像素是图像的基本采样单位,不是一个确定的物理量,因为像素点的物理大小是不确定的。像素也不是一个具体的点或者小方块(尽管可以用点或者小方块呈现),是一个抽象的概念。3)分辨率分辨率是屏幕像素的数量,一般用屏宽像素乘以屏高像素表示。描述iPhone6的屏幕分辨率是750x1334,就是iPhone6的屏幕是由750列和1334行的像素点排列组成。每个像素点发出不同颜色的光,构成所看到的画面。在PC时代,分辨率越高,意味着屏幕越大,因为PC具有固定的PPI。但智能手机的屏幕就不是如此了,因为手机的像素密度是不一样的。2,网点密度与像素密度1)网点密度(DPI)DPI常用于“设备参数”描述(如扫描仪和打印机)

  • Flutter启动流程初探

    最近开始研究Flutter了,俗话说工欲善其事必先利其器,在正式运用Flutter之前肯定要先了解了解它的工作机制,于是开始了Flutter以及Dart的源码学习之旅,这次就简单的分析一下Flutter的启动流程,作为记录~helloworldvoidmain()=>runApp(newMyApp()); classMyAppextendsStatelessWidget{ @override Widgetbuild(BuildContextcontext){ returnnewMaterialApp( title:'FlutterDemo', theme:newThemeData( primarySwatch:Colors.blue, ), home:newMyHomePage(title:'FlutterDemoHomePage'), ); } }复制上面是官网上一个demo的一部分,我们可以看到其中有一个main函数,内部使用了runApp并将业务视图顶层的MyApp传了进去。这样我们的Flutter界面就能展示出来了。runAppv

  • 构建端到端的开源现代数据平台

    了解使用开源技术构建现代数据栈的详细指南。 在过去的几年里,数据工程领域的重要性突飞猛进,为加速创新和进步打开了大门——从今天开始,越来越多的人开始思考数据资源以及如何更好地利用它们。这一进步反过来又导致了数据技术的“第三次浪潮”。 “第一次浪潮”包括ETL、OLAP和关系数据仓库,它们是商业智能(BI)生态系统的基石,无法应对大数据的4V的指数增长。 由于面向BI的栈的潜力有限,我们随后见证了“第二次浪潮”:由于Hadoop生态系统(允许公司横向扩展其数据平台)和ApacheSpark(为大规模高效的内存数据处理打开了大门)。 称之为“第三次浪潮”的是这个我们不再担心可扩展性或分布式存储的时代。相反我们正在成熟的分布式数据平台之上构建新功能,现在我们可以考虑元数据管理、大规模数据发现和数据可靠性等主题。我们正处于可互换的SaaS模块、基于云的平台、ELT和民主化数据访问的时代。欢迎来到现代数据栈浪潮。 本文中我们将从头开始构建一个端到端的现代数据平台,完全依赖开源技术和云提供商提供的资源。这篇文章还附有一个GitHub存储库,其中包含构建平台所需的必要代码和基础设施即代码(IaC

  • 从零开始Blazor Server(8)--增加菜单以及调整位置

    这篇干啥这篇文章主要是把前面的一些东西稍微调整一下,使其更适合后面的内容。主要是两个事,一个是把原来的PermissionEntity直接变成MenuEntity,直接让最后一级是菜单,这样后面就简单很多。另外增加一些默认的菜单为后面的文章做准备。另外就是调整一下Pages里面的目录结构,让我们不用每个页面都去加@attribute[Authorize]处理目录结构之前的内容里,我们最后还是用了Furion自带的方法来处理成策略授权了,所以我们正常的话需要每个页面都加上@attribute[Authorize]。但是这样太麻烦了,幸好微软给我们提供了一个_Imports.razor的东西,这个文件是目录级的,我们可以在某层目录下添加,然后此目录和它的子目录都会受影响。所以我们就需要把Login和其他的页面分开,因为我们的Login页面是不需要登录的,而且分开以后更清晰。这里在Pages下面新建两个目录,一个叫Account,一个叫Admin。这里把Login.razor放到Account目录下,把其他的razor文件都放到Admin下面。这里注意不要移动那两个cshtml文件,因为那两

  • 漫谈JavaScript中的提升机制(Hoisting)

    前言 刚接触到JavaScript的时候,便知道JavaScript是按顺序执行的,是如浏览器的解析DOM树一样的流程,解析DOM结构的时候,如果遇到JS脚本或者外联脚本便会停止解析,继续下载脚本之后,执行脚本,然后再解析DOM。 然而,却因此常常碰到问题。 看如下代码以及输出: varname; console.log(name);//undefined name='tom'; age=10; varage; console.log(age);//10 复制    上面的代码让我们产生了疑惑,我们仅仅声明了name的时候,打印出来值是undefined,按理说,重新声明age之后,age的值应该也是undefined才对,但是输出来的却是10。这究竟是怎么回事儿呢? 我们的通用解释是,遇到了变量提升。 而这样的情况,我们在函数中也会看到,请看下面代码: log(); console.log(name); varname='tom'; functionlog(){ console.log('thisislog'); } 复制    上面代码的输出结果是什么? 输出结果: t

  • C++入门经典-例8.2-构造函数的访问顺序

    1:父类和子类中都有构造函数和析构函数,那么子类对象在创建时是父类先进行构造还是子类先进行构造?同样,在子类对象释放时,是父类先进行释放,还是子类先进行释放?这都是有先后顺序的。答案是当从父类派生一个子类并声明一个子类的对象时,它将先调用父类的构造函数,然后调用当前类的构造函数来创建对象;在释放之类对象时,先调用的是当前类的析构函数,然后是父类的析构函数。 2:实例代码如下: //8.2.cpp:定义控制台应用程序的入口点。 // #include"stdafx.h" #include<iostream> usingnamespacestd; classCEmployee//定义CEmployee类 { public: intm_ID;//定义数据成员 charm_Name[128];//定义数据成员 charm_Depart[128];//定义数据成员 CEmployee()//定义构造函数 { cout<<"CEmployee类构造函数被调用"<<endl;//输出信息 } ~CEmployee()//析构函数 { cout<<

  • 支付宝新版SDK-PC扫码支付-手机浏览器H5支付

    一、前言 支付宝支付—沙箱环境使用 支付宝新版SDK-PC端扫码支付+手机浏览器H5支付「本文」 PC端扫码支付,其实就是就是电脑网站支付,本文基于支付宝沙箱环境,不了解的可以看一下上边的链接。 PS:本文是基于支付宝新版SDK重写的,用法非常简单,之前的旧版SDK就别参考了~ 本文环境: JDK1.8 IDEA2020.3.2 SpringBoot2.2.2 alipay-easysdk2.2.0 支付宝沙箱环境 二、引入依赖 源码地址:https://github.com/niceyoo/alipay-demo 创建一个SpringBoot应用(有基础的建议直接看↑源码),在pom中引入如下依赖: <!-- alipay --><dependency>    <groupId>com.alipay.sdk</groupId>    <artifactId>alipay-easysdk</artifactId>

  • 使用face-api.js实现人脸识别(一)

    功能   第一阶段实现对图片中人脸的识别并打上标签(比如:人名)   第二阶段使用摄像头实现对人物的识别,比如典型的应用做一个人脸考勤的系统 资源 face-api.js https://github.com/justadudewhohacks/face-api.js/   Face-api.js是一个JavaScriptAPI,是基于tensorflow.js核心API的人脸检测和人脸识别的浏览器实现。它实现了一系列的卷积神经网络(CNN),针对网络和移动设备进行了优化。非常牛逼,简单好用 filepond https://github.com/pqina/filepond   是一个JavaScript文件上传库。可以拖入上传文件,并且会对图像进行优化以加快上传速度。让用户体验到出色、进度可见、如丝般顺畅的用户体验。确实很酷的一款上传图片的开源产品 fancyBox https://fancyapps.com/fancybox/3/   是一个JavaScript库,它以优雅的方式展示图片,视频和一些html内容。它包含你所期望的一切特性—

  • 接圈的作用和缺点

    在很多视觉项目中,如果想要将视野缩小,一种方式是换用长焦镜头;另一种方式则是通过加接圈的方式来实现。那么,接圈到底改变的是什么参数,能够使图像进行放大呢?核心公式1s1s+1s01s0=1f1f       上式可以说是镜头第一公式,做图像或者光学的人都记下来。其中的s代表物距,即镜头下边到物体的距离。s0代表像距,即镜头上边到成像Sense的距离。f是镜头的焦距。       由上式可知,增加接圈实际上增加了相距s0,因此,物距s减小。即工作距离减少。       同时,由于焦距没有变化,而工作距离减小了,因此,视野也减小了,即图像放大了。其原理如下图所示:  增加接圈的作用加接圈使相距增大加接圈使工作距离变小加接圈使视野变小加接圈使图像放大增加接圈的缺点     如上所示,加接圈的好处挺多的,但是,加接圈也

  • netcat/nmap: 网络工具中里的“瑞士军刀”

    目录1.netcat1.1.常用功能一览1.2.验证端口的开放1.3.端口扫描1.4.连接远程系统1.5.作为聊天工具1.6.作为代理/转发数据1.7.通过nc进行端口转发1.8.传输文件1.9.通过nc创建后门2.nmap:专用于IP扫描工具2.1.仅扫描IP地址(使用ping)2.2.扫描目标网段的常用TCP端口2.3.检查IP范围192.168.10.2~192.168.10.4内,有哪些主机开放22端口2.4.检查目标主机的操作系统类型(OS指纹探测)2.5.检查目标主机上某个端口对应的服务程序版本2.6.指定扫描目标主机的哪些端口2.7.检测目标主机是否开放DNS、DHCP服务2.8.检测目标主机是否启用防火墙过滤 cnblog:nc工具使用 1.netcat netcat,别名ncat或nc,拥有Windows和Linux的版本。因为它短小精悍,功能实用,被设计为一个简单、可靠的网络工具,可通过TCP或UDP协议传输读写数据。同时,它还是一个网络应用Debug分析器,因为它可以根据需要创建各种不同类型的网络连接。 1.1.常用功能一览 nc的常用的几个参数如下所列:

  • WebSocket使用

    WebSocket使用 html5定义WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。 为实现推送效果,可以使用ajax轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。 图解区分websocket与ajax轮询 varurl='ws://localhost:9998/echo' varsocket=newWebSocket(url,[protocol]) //第一个参数url为请求地址,第二个protocol为可选,指定了可接受的协议。 socket.onopen=function(){ //websocket建立连接时触发。 } socket.onmessage=function(){ //客户端接受服务端数据时候触发 } socket.onerror=function(){ //通讯时发生错误时

  • QT学习1

    一、程序安装 Qt5.12下载网址: http://download.qt.io/archive/qt/5.12/5.12.2/ 选择Windows平台,Linux和Mac平台类似 下载好之后的安装包:  2、软件安装   管理员运行安装程序         账号密码注册:https://login.qt.io/login    注意密码要大小写和数字   邮箱验证:https://mail.qq.com/   信息录入:用户名、公司、地址         等待安装完成 个人习惯配置修改1(菜单:工具->选项)      ../%{JS:Util.asciify("build-%{CurrentProject:Name}-%{CurrentKit:FileSystemName}-%{CurrentBuild:Name}

  • android开发 锁屏 真正的锁屏,是go锁屏那种。

    想做个锁屏界面很久了,最近一周,历经千辛万苦,越过种种挫折,终于完美实现了这一要求,在此将锁屏思路分享出来。 注意:这不是什么一键锁屏,是类似“go锁屏”那样的锁屏界面。   准备:本程序共需要 两个activity:home、main。 一个service:myService 一个receiver:bootReceiver 一个layout:layout 其中home作为屏幕home键专用的activity,main则是主要的展示锁屏界面的activity。 service用于接收锁屏/解锁广播,layout则是main所需要展示的界面。   思路: !注意:以下代码没有顺序联系,具体请参考源码!   1,给程序添加服务,当此服务接收到 锁屏/解锁广播时,关闭系统锁屏界面,打开自己的锁屏界面。   关键代码: /onReceive中: keyguardManager=(KeyguardManager)context.getSystemService(context.KEYGUARD_SERVICE); keyguardLock=k

  • js中java式的类成员

    functionRange(from,to,x){ //实例(对象)字段 this.x=x; } //类字段 Range.Y="类字段"; //类方法 Range.s=function(){ return'类方法'; }; Range.prototype={ constructor:Range, //实例方法 slff:function(){ return"实例方法"; } }; vars=newRange(1,3,"实例字段"); console.log(s.x); console.log(s.slff()); console.log(Range.Y); console.log(Range.s()); console.log(sinstanceofRange);复制 构造函数对象(Range)       构造函数(对象)为Javascript的类定义了名字.任何添加到这个构造函数对象中的       属性都是类字段和类方法(如果属性值是函数的话就是类方法).

  • (转)Android 系统 root 破解原理分析

    现在Android系统的root破解基本上成为大家的必备技能!网上也有很多中一键破解的软件,使root破解越来越容易。但是你思考过root破解的原理吗?root破解的本质是什么呢?难道是利用了Linuxkernal的漏洞吗?本文将简单对root的破解原理进行分析。 网上有一篇文章已经对root破解的基本原理进行了简单介绍,大家可以先参考一下《androidroot权限破解分析》,本文只能说对root原理进行了方向性的描述,但是在一些具体的方面没有描述清楚。本文将会对其进行一些必要的扩展和补充。 如果你进行过程序开发,在root过的手机上面获得root权限的代码如下: Processprocess=Runtime.getRuntime().exec("su"); DataOutputStreamos=newDataOutputStream(process.getOutputStream()); ...... os.writeBytes("exit\n"); os.flush();复制    从上面代码我们可以看到首先要运行su程序,其实root的秘密都在su

  • Python实现根据时间移动/复制一个文件夹的文件--模拟大并发数据

      最近,在做项目的时候遇到一个问题,大体就是要将大几万的图片,移动到另一目录下,为了验证开发写的脚本正确性,从而达到图片的识别率、漏识别率。模拟了该场景。。。。 #!/usr/bin/envpython #-*-coding:utf-8-*- #@Time:2021/3/217:08 #@Author:Administrator #@File:mytest.py importos importshutil importtime defget_files(): count=0 filenames=os.listdir('/data/image_src_bak') forfilenameinfilenames: print(filename) src=os.path.join('/data/image_src_bak',filename) dst=os.path.join('/data/image_src',filename) shutil.move(src,dst)    #shutil.copy(src,dst) ifcount%10==0: time.sleep(10) pr

  • PC端适应屏幕分辨率

    如何让HTML页面适应不同的屏幕分辨率 1.根据不同的分辨率,加载不同的css样式文件(一般不用) ①针对800、1280、1440、1600、1920等分辨率,创建不同的css文件。然后在各种分辨率css文件下,写css样式表。 针对一个页面,写多css样式表,按照不同的要求,有些要求适配1280~1920分辨率,各个分辨率之间,只对页面上的元素进行宽高、尺寸、位置等进行调整,整体的框架是相似或者说是相同的。 通常是先完成一个分辨率下的css样式表。然后在这个基础之上,对其他分辨率进行调整。 ②加载方式。 在HTML页面的<head></head>标签中,插入<script>代码,在不同的分辨率下,加载不同的css样式表。 注意这里的js一定要写在<head></head>标签里面,这样在加载页面内容之前,可以提前把css样式表加载出来 <script> //分辨率大于等于1680,大部分为1920的情况下,调用此css if(window.screen.width>=1680){ document.wr

  • 单分派与多分派

    方法的调用者的类型(父类型)称作静态类型。调用者最终类型(本身的类型)称作实际类型。 当确定方法的版本是通过调用者实际类型+方法参数中的类型才能确定方法版本时候,这种分派称作多分派。只是依据调用者和方法参数,叫做单分派。 分派是站在通过类型确定方法版本的角度上说的。 java是静态多分派,动态单分派的。 首先,静态分派是发生在编译阶段的。在编译阶段如果要确定方法的版本,需要知道调用者的实际类型与参数类型。所以是多分派的。 多分派是发生在编译阶段的,此时由于编译过后已经知道了参数的实际类型,所以此时只需要知道方法调用者的实际类型就可确定出方法的唯一版本,所以动态分派一定是单分派。

相关推荐

推荐阅读