ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SQL Server备份与还原保姆级教程:从备份原理到实战排雷

SQL Server备份与还原保姆级教程:从备份原理到实战排雷 干了这么多年SQL Server运维我越来越觉得备份和还原这事儿平时看着不起眼真到了关键时刻就是救命稻草。今天这篇保姆级教程就围绕“SQL Server数据库的备份和还原”这条主线把从备份原理、手工操作、自动化配置到还原实战、故障排雷的完整链路都捋一遍。不管你是刚入门的新手DBA还是要兼职管数据库的开发、运维、测试只要照着做都能把这块基本功练扎实。先提醒一句数据库备份不能简单理解成“复制几个文件”。直接拷贝mdf和ldf文件这在数据库在线运行状态下几乎等于没有备份因为文件写入顺序不一致还原出来很可能是损坏的或者是状态不一致的库。真正的备份必须由SQL Server的备份引擎来做它知道怎么在一致性点上生成备份集。理解了这一点后面所有的操作都顺理成章。1. 备份方案的底层逻辑先搞清楚备份类型和恢复模式1.1 为什么备份策略一定要提前设计很多人第一次备份就是右键数据库点一下“备份”完事儿以为万事大吉。但遇到真实故障要还原时才发现要么没有日志备份链要么差异备份无法应用恢复点根本达不到预期。这就好比出门旅游只拍了第一张照片后面所有精彩片段全丢了。在设计备份方案之前必须要搞清楚三个基本概念完整备份、差异备份、事务日志备份。可以这样类比完整备份是给整个数据库拍一张“全家福”差异备份是记录“从上次全家福之后所有新增的变化”事务日志备份则是把每天发生的每一笔操作“流水账”记下来。还原的时候先恢复完整备份再按顺序叠加差异备份和日志备份就能把数据库恢复到任意一个时间点。还有一个前置条件必须明确——数据库的恢复模式。SQL Server提供了三种恢复模式简单恢复模式、完整恢复模式、大容量日志恢复模式。它们的区别直接决定了你能做哪些备份、能恢复到什么程度。恢复模式日志备份时间点恢复适用场景简单恢复模式不支持不支持只能恢复到最近一次完整或差异备份开发库、测试库、可容忍丢失数据的库完整恢复模式支持支持可恢复到日志备份覆盖范围内的任意时间点生产库、核心业务库大容量日志恢复模式支持但有限制部分场景支持大容量操作后日志增长较快大批量导入数据、索引重建等维护窗口如果你的生产库设置成简单恢复模式那意味着日志备份根本没有一旦数据文件损坏最多只能恢复到上一次备份的时间点中间所有事务全部丢失。所以我的建议很明确核心业务库一定要用完整恢复模式并且定期做日志备份。日志备份的频率根据业务容忍度来定常见的是每15分钟、30分钟或1小时一次。1.2 备份验证的两道安全关CHECKSUM 与 VERIFYONLY备份文件生成了不代表一定能用。磁盘坏道、网络传输中断、备份过程中异常断电都可能导致备份文件物理损坏。所以在备份阶段就要加两道保险。第一道是BACKUP ... WITH CHECKSUM备份引擎在读数据页的时候会计算校验值并写入备份集这样在还原时就能检测到数据页是否损坏。第二道是RESTORE VERIFYONLY FROM DISK 备份文件路径这个命令不实际还原数据库只读取备份文件头并检查备份集的完整性。这两步能挡掉大部分“备份文件坏了、不能还原”的坑。我从实际项目里学到的教训是千万别省这两步。有一次客户环境做例行备份任务一直显示成功结果真到要还原的时候发现备份文件里有几个页校验失败根本起不来。从那时起我所有的自动化备份脚本里都强制加上CHECKSUM并且每天早上自动跑一遍RESTORE VERIFYONLY一旦校验失败立刻告警。对于重要的系统强烈建议定期做一次“还原演练”光验证备份文件还不够要真正在一台测试服务器上把库还原起来确认应用能正常连上这才是真的万无一失。2. 手工备份实操从SSMS界面到T-SQL命令2.1 用SSMS图形界面完成一次完整备份对于新手来说最直观的方式就是用SSMS(SQL Server Management Studio)图形界面操作。步骤并不复杂但每一步的选项都有讲究。在SSMS对象资源管理器中展开“数据库”右键点击你要备份的数据库选择“任务” - “备份”。这时会弹出备份数据库对话框备份类型选择“完整”备份组件选“数据库”目标位置默认是磁盘。点击“添加”可以指定备份文件的路径和文件名。我习惯的命名规则是数据库名_备份类型_日期_时间.bak例如OrderDB_FULL_20250610_140000.bak这样一眼就能看出是什么时候的什么备份。这里有几个选项要特别留意。“备份到现有备份集”或“备份到新备份集”这个选择对应的是T-SQL里的INIT/NOINIT参数。默认情况下SQL Server会追加到同一个备份文件里也就是一个文件里可能会存在多个备份集。如果你希望每次备份都覆盖旧文件就要勾选“覆盖所有现有备份集”。但在生产环境里我更推荐每次生成独立的备份文件便于管理也避免误覆盖。“压缩备份”这个选项建议开启可以显著减小备份文件体积。压缩备份在SQL Server 2008企业版及以后版本中广泛使用实测同一个数据库压缩后体积能减少到原来的三分之一甚至更低代价是备份时CPU使用率会升高。对于线上交易系统如果服务器CPU压力不大压缩备份非常划算。2.2 T-SQL备份命令与参数详解图形界面适合临时手动操作但真正的生产环境还是要用脚本。T-SQL备份命令的核心语法非常简洁但每个参数背后都有不同的使用场景我逐个拆解一下。假设要对OrderDB做一次完整备份并压缩备份集BACKUP DATABASE [OrderDB] TO DISK NE:\Backup\OrderDB_FULL_20250610_140000.bak WITH COMPRESSION, INIT, CHECKSUM, STATS 10;这里面的参数逐个解释一下。INIT表示覆盖目标文件原有内容等价于图形界面里的“覆盖所有现有备份集”。如果不加INIT默认是追加NOINIT同一个文件里会累积多个备份集。日常备份脚本建议用INIT但是要特别留意备份文件名不能重复否则会互相覆盖所以文件名里最好带上时间戳。COMPRESSION开启备份压缩能大幅缩小备份文件占用空间。CHECKSUM开启备份校验在备份过程中对数据页计算校验和为后续还原提供完整性校验的基础。STATS 10表示每完成10%就输出一条进度信息方便在消息窗口里观察备份进度。如果你用脚本任务去执行还能把输出写到日志文件里方便排查。还要重点提一个容易被忽视的参数COPY_ONLY。如果你在完整恢复模式下平时靠“完整备份日志备份”做恢复策略那么在某个时间点因为特殊需求临时做了一次完整备份这就会打断日志备份链——因为后续还原时SQL Server会认为你可以从这次新备份开始做差异或日志还原逻辑上容易出错。如果你不想让这次备份影响现有的备份链就要加COPY_ONLYBACKUP DATABASE [OrderDB] TO DISK NE:\Backup\OrderDB_COPYONLY.bak WITH COPY_ONLY;加了COPY_ONLY的备份不会影响LSN链不会打断差异备份的基准也不影响后续日志备份的连续性。我用这个参数最多的场景是给开发环境同步一份生产数据或者在大版本升级前做一次快速安全快照。2.3 用维护计划实现自动备份手动备份永远不是终点生产环境必须自动化。SQL Server提供了一套维护计划Maintenance Plan工具通过图形化界面就能配置周期性的完整备份、差异备份和日志备份任务。在SSMS中展开“管理” - “维护计划”右键“维护计划向导”就能创建一个维护计划。向导会引导选择维护任务比如“备份数据库完整”、“备份数据库差异”、“备份数据库事务日志”还可以加“清除维护任务”来自动删除过期备份文件。这种方式适合不愿意写代码的运维人员配置速度快报表直观。但维护计划有个典型的坑它默认生成的备份文件名是固定的如果配置不当后续备份会一直往同一个文件里追加文件越来越大还原时也容易搞混。我建议在“备份数据库”任务的“备份文件扩展名”和“备份压缩”设置里仔细检查同时配合“清除维护任务”设置合理的保留天数。如果你更习惯用代码管理也可以直接用SQL Server代理作业SQL Server Agent Job去跑T-SQL脚本。比如每天凌晨1点跑一次完整备份每30分钟跑一次日志备份。代理作业的方式更灵活也方便纳入版本管理我就是这样做的。相比维护计划脚本方式更容易定制比如备份完成后把备份文件传送到异地服务器或者通过邮件通知备份结果。3. 还原实操详解从图形界面到T-SQL全流程3.1 还原前的关键准备工作还原操作比备份更需要谨慎因为一旦操作不当可能会覆盖现有的数据库。所以还原之前一定要回答清楚三个问题还原到哪个数据库覆盖还是新建需要恢复到哪个时间点当你准备还原一个生产库的时候最好先确认目标服务器上是否存在同名数据库。如果存在SQL Server默认会提示你“现有数据库会被覆盖”这时可以选择“替换现有数据库WITH REPLACE”。但用了WITH REPLACE之后原数据库的所有内容都会被覆盖操作前务必确认备份文件是你要的那个版本。另外还有一个常见问题就是其他会话正在连接着数据库导致还原时提示“数据库正在使用”无法获得独占访问权。解决办法是把所有连接断开或者把数据库先设为单用户模式再执行还原。获取当前有哪些连接可以用这个查询SELECT session_id, login_name, status, host_name, program_name FROM sys.dm_exec_sessions WHERE database_id DB_ID(NOrderDB);如果要强制断开某个会话可以用KILL session_id命令。但要注意生产系统上千万不要随便KILL掉关键应用的连接否则可能引发业务中断。稳妥的做法是选在维护窗口操作或者通知应用团队先把连接池停掉。3.2 SSMS还原向导的完整操作流程用SSMS还原也很简单。右键目标数据库可以是同名的也可以是新建的一个空白库选择“任务” - “还原” - “数据库”这时会进入还原数据库界面。在“常规”页先选“源设备”然后点击浏览按钮找到你的备份文件。SQL Server会读取备份文件头列出这个文件里包含的所有备份集。这里要注意一个文件里可能包含多个备份集你要选择正确的那个。选中备份集后“目标数据库”填上你要还原成的库名。如果服务器上已经存在同名库并希望覆盖就在“选项”页里勾选“覆盖现有数据库(WITH REPLACE)”。“选项”页里还有一个“恢复状态”设置默认是“回滚未提交的事务使数据库处于可用状态RESTORE WITH RECOVERY”这是最常用的最终还原。但如果后面还要继续应用差异备份或日志备份就要选“不对数据库执行任何操作RESTORE WITH NORECOVERY”。这一点很多人容易搞混——如果最后一步用了WITH RECOVERY就无法继续追加日志备份了。3.3 T-SQL还原还原路径、改名与文件迁移T-SQL还原比图形界面更灵活尤其是当目标服务器与源服务器数据文件路径不一致时或者需要把数据库还原成另一个名字时图形界面反而不太方便。这里分享一个核心命令RESTORE DATABASE。先看一条常见的完整还原命令RESTORE DATABASE [OrderDB] FROM DISK NE:\Backup\OrderDB_FULL_20250610_140000.bak WITH RECOVERY, STATS 10;如果目标服务器上数据文件路径和原来不同或者你不想覆盖原库想还原成另一个名字就需要用WITH MOVE指定逻辑文件名映射到新物理路径RESTORE DATABASE [OrderDB_Test] FROM DISK NE:\Backup\OrderDB_FULL_20250610_140000.bak WITH MOVE OrderDB TO ND:\Data\OrderDB_Test.mdf, MOVE OrderDB_log TO ND:\Log\OrderDB_Test_log.ldf, RECOVERY;这里的OrderDB和OrderDB_log是备份集里的逻辑文件名。怎么查到逻辑文件名两种办法一是执行RESTORE FILELISTONLY FROM DISK 备份文件路径直接列出备份集里所有文件二是在SSMS还原向导的“文件”页查看。我第一次做跨机器还原时就卡在逻辑文件名对不上报了一堆错误后来才明白要先查FILELISTONLY。另外还有NORECOVERY参数用于多步还原过程。一个典型的场景是先还原完整备份再追加差异备份最后追加日志备份在最后一步才用RECOVERY让数据库上线。每一步的命令如下-- 第1步还原完整备份保持数据库为“正在还原”状态 RESTORE DATABASE [OrderDB] FROM DISK NE:\Backup\OrderDB_FULL_20250610_140000.bak WITH NORECOVERY; -- 第2步还原差异备份 RESTORE DATABASE [OrderDB] FROM DISK NE:\Backup\OrderDB_DIFF_20250610_113000.bak WITH NORECOVERY; -- 第3步还原日志备份并把数据库带回可用状态 RESTORE LOG [OrderDB] FROM DISK NE:\Backup\OrderDB_LOG_20250610_123000.trn WITH RECOVERY;注意在每步用NORECOVERY后数据库处于“正在还原”状态应用连不上属正常现象。只有最后一步换成RECOVERY数据库才会能访问。如果想做一个只读的还原副本用于报表查询或给开发联调用可以在最后一步用STANDBY参数RESTORE DATABASE [OrderDB_Report] FROM DISK NE:\Backup\OrderDB_FULL_20250610_140000.bak WITH STANDBY NE:\Backup\OrderDB_Standby.und;STANDBY模式可以让数据库处于只读状态同时保留继续还原日志的能力。每次想更新报表库数据时不需要删除数据库重建直接继续追加日志备份就行非常省事。这个方案我用来做只读从库比搭建AlwaysOn可用性组要轻量得多适合中小型系统。3.4 时间点恢复把数据库还原到某个具体时刻完整恢复模式下最有价值的操作就是“时间点恢复”。比如你上午10点误删了一张表把数据恢复到9点59分损失几乎为零。还原到具体时间点的逻辑很简单关键在最后一步恢复日志时使用STOPAT参数RESTORE DATABASE [OrderDB] FROM DISK NE:\Backup\OrderDB_FULL_20250610_030000.bak WITH NORECOVERY; RESTORE LOG [OrderDB] FROM DISK NE:\Backup\OrderDB_LOG_20250610_093000.trn WITH RECOVERY, STOPAT N2025-06-10T09:59:00;这里要注意日志备份文件的顺序必须正确从早到晚依次还原。SQL Server会检查LSN链如果你跳过了某个日志备份就会报错提示“LSN too recent”之类的信息。另外STOPAT指定的时间必须落在最后一份日志备份覆盖的时间段内否则会报错。如果误操作发生在10:00你把备份还原到09:59那10:00之后的日志备份就不需要再还原了。这里有一个非常关键的实操经验做时间点恢复时尽量把可能包含误操作的那一份日志备份文件也带上用STOPAT截断到误操作前一刻。比如误操作在10:02:00你就该把10:00-10:10的日志备份也加到还原序列里然后用STOPAT 10:01:59。这样才能最大程度找回数据。4. 差异备份和日志备份组合起来才是完整方案4.1 差异备份缩短还原时间的利器完整备份是基础但如果每天只做一次完整备份万一第二天中午出故障就会丢失当天所有数据而且还原时间可能要几小时。这时候差异备份就派上用场了。差异备份记录的是自上一次完整备份以来所有变化的数据页。它的特点是体积通常比完整备份小备份速度快还原时只需要先还原完整备份再还原最近一次差异备份即可不需要把之前的多个日志备份都搬出来。举个例子周一凌晨做了完整备份周二凌晨做了差异备份周三上午出现故障还原时先恢复周一完整备份再恢复周二差异备份就可以快速回到周二的状态。如果需要更精确到周三上午可以继续追加周二的日志备份。差异备份的T-SQL命令是BACKUP DATABASE [OrderDB] TO DISK NE:\Backup\OrderDB_DIFF_20250611_023000.bak WITH DIFFERENTIAL, COMPRESSION, CHECKSUM;还原差异备份的步骤和前面讲到的一致先完整备份加NORECOVERY再差异备份加RECOVERY。注意差异备份只能还原最近一次你不需要把周一的差异和周二的差异都还原一遍只需要最后一次。这是很多新手容易搞混的地方——差异备份不是累计所有的差异而是基于最后一次完整备份的累积差异。4.2 事务日志备份备份链的生命线日志备份记录的是自上一次日志备份之后产生的所有事务日志记录。它的粒度最细可以把数据库恢复到任意时间点代价是需要按顺序逐份还原文件数量多管理难度高。在完整恢复模式下如果长时间没有做事务日志备份日志文件会不断增长甚至撑爆磁盘空间。所以生产环境建议至少每小时做一次日志备份繁忙系统甚至可以每10-15分钟一次。日志备份本身非常快因为只是备份已提交的事务日志内容数据量相对较小。日志备份的T-SQL命令是BACKUP LOG [OrderDB] TO DISK NE:\Backup\OrderDB_LOG_20250610_113000.trn WITH COMPRESSION, CHECKSUM;还原日志备份时最关键的是保证顺序连续。SQL Server通过LSN日志序列号来标识每一条日志记录日志备份文件里记录了起始LSN和结束LSN。如果你尝试还原一个与当前还原链不连续的日志备份SQL Server会直接报错提示“LSN不匹配”。这是它的保护机制避免你乱序操作。4.3 一次完整的恢复演练全备差异日志为了让你真正明白这套组合拳怎么打我模拟一个具体故障场景。假设某个核心库OrderDB的备份策略是每天凌晨3:00做完整备份每天上午11:00做一次差异备份每30分钟做一次日志备份。现在数据库在当天下午14:20发生故障数据文件损坏。你要执行以下恢复步骤还原当天凌晨3:00的完整备份使用WITH NORECOVERY还原当天上午11:00的差异备份使用WITH NORECOVERY还原当天11:30、12:00、12:30、13:00、13:30、14:00的日志备份全部使用WITH NORECOVERY如果14:00之后的日志备份也存在但由于故障可能没生成那就还原到最后一个可用的日志备份即可使用WITH RECOVERY让数据库上线。如果你需要把数据恢复到14:00而不是14:20那么最后的日志备份使用STOPAT N2025-06-10T14:00:00即可。如果14:00的日志备份还没生成就只能恢复到13:30的状态丢失半个多小时的数据。这也就理解了为什么日志备份频率越高RPO恢复点目标越好。这个流程我建议每个DBA都要在自己的测试环境里演练至少一次。因为备份策略再完美没有实际演练过真的遇到故障时容易手忙脚乱搞错顺序就会浪费宝贵的恢复时间。5. 备份还原常见故障与排查技巧5.1 数据库一直显示“正在还原”无法访问这是最常见的状况。执行完还原命令后数据库一直处于“正在还原”状态应用连不上甚至过了很久还是这样。原因通常有两种一是你最后一次还原使用了NORECOVERY数据库本来就应该保持这个状态等待后续日志还原二是还原过程中某个日志备份应用失败导致数据库无法自动进入可用状态。解决办法如果是误用了NORECOVERY重新执行一次相同的还原命令但把NORECOVERY改成RECOVERY。比如RESTORE DATABASE [OrderDB] WITH RECOVERY;注意这条命令不需要再指定备份文件它只是让处于正在还原状态的数据库完成回滚并上线。执行后如果没有任何错误数据库状态会变为“在线”。5.2 还原时提示“LSN链断裂”或“备份集与现有数据库不匹配”这种报错往往是因为你试图还原的备份文件与目标数据库当前状态不一致。比如你从备份集中还原但目标数据库已经有过新的日志记录SQL Server认为你再继续还原会造成数据不一致于是拒绝操作。解决办法是把目标数据库先删除前提是你确认不需要保留现有数据或者使用WITH REPLACE强制覆盖。不过使用WITH REPLACE要非常慎重因为它会跳过一些安全校验可能会把原本想保留的数据也冲掉。我个人的原则是只有在明确知道目标库可以被覆盖时才用WITH REPLACE并且先用RESTORE FILELISTONLY确认备份文件内容。5.3 还原时默认路径不存在或权限不足在不同服务器之间迁移数据库时经常遇到目标服务器磁盘结构不同备份文件里的原始路径不存在。这时会报“目录查找失败”之类的错误。解决方式就是前面提到的WITH MOVE参数把数据文件和日志文件重新映射到目标服务器上存在的路径。还有一个经常被人忽视的点是SQL Server服务账号对目标目录的权限。如果你是Windows服务方式运行的SQL Server服务账号是类似NT Service\MSSQLSERVER或域账号那么它必须有对目标目录的“读/写”权限否则还原会失败报“操作系统错误5拒绝访问”。解决方法是给服务账号添加对应目录的权限或者把备份文件放到SQL Server默认的备份目录下。5.4 SQL Server服务无法启动wait on the database engine recovery handle failed这个错误在热词里也出现了确实是个灾难级问题。报这个错通常意味着SQL Server服务启动时数据库实例的恢复流程卡住或直接失败常见诱因包括master数据库损坏、tempdb路径不存在、磁盘空间不足、或者某个非系统库在启动恢复时遇到严重错误。遇到这个错误首先不要慌可以先看Windows事件查看器里的“应用程序”日志找到对应SQL Server的错误详细信息。常见的一条修复思路是用单用户模式启动SQL Server修复或重置master数据库。但这个过程比较专业如果没有经验建议找DBA或微软支持协助。如果只是某个普通业务库导致恢复失败另一个技巧是使用“最简恢复”启动参数-f和-m跳过启动时的自动恢复先把服务拉起来再单独处理问题库。但这种方式会让SQL Server进入单用户模式业务不可用只能作为应急手段。我对这类问题的经验是数据库备份必须做到位尤其是master库的备份否则真出这种故障时恢复成本很高。5.5 备份文件损坏或验证失败备份文件放在磁盘上常年不动也可能因为坏道、意外删除、被安全软件隔离等原因损坏。这时候RESTORE VERIFYONLY就能提前发现问题。如果校验失败文件也没有其他副本那就只能认栽。所以备份文件的异地备份和定期验证绝对不能省这也是备份策略里被低估但极其重要的一环。我习惯在备份完成后写一个任务自动把备份文件复制到另一台NAS或对象存储上同时每天执行一次RESTORE VERIFYONLY。很多企业“备份做了几年一次都没还原过”结果真正用到时往往发现备份有问题这种案例太多了希望大家别踩同款坑。6. 备份策略规划与个人经验建议6.1 根据RPO/RTO确定备份频率任何备份策略都不能脱离业务目标。一句话说清楚RPO决定了你能容忍丢失多少数据RTO决定了你能容忍停机多久。如果你能接受丢失1小时数据那日志备份至少一小时一次如果必须控制在15分钟内那日志备份就要做到15分钟一次甚至更频繁。RTO则决定了你该用完整备份差异备份来缩短还原时间还是直接上AlwaysOn可用性组这类高可用方案。对于大多数中小型系统我建议的基准方案是备份类型频率保留时间完整备份每天一次业务低峰期最近7天到30天差异备份每天1-2次或每4-6小时一次最近7天日志备份每15-60分钟一次最近3-7天这套组合既能保证快速还原又能把丢失窗口控制在小时级。如果业务要求更高再往上加频率或引入高可用方案。6.2 定期检查备份结果和磁盘空间自动化任务不是配好就完事还要有监控。我见过太多“备份任务一直失败但没人发现”的情况。最简单的检查方式是用SQL Agent自带的通知功能或者查询msdb库中的备份历史表来核对任务是否成功SELECT database_name, type, backup_start_date, backup_finish_date, backup_size, first_lsn, last_lsn FROM msdb.dbo.backupset WHERE database_name NOrderDB ORDER BY backup_start_date DESC;这个查询能帮你快速确认最近备份是否成功、备份文件大小是否异常波动。如果某天备份文件突然变得特别小很可能数据有隐患或者事务日志异常。另外数据库服务器的磁盘空间也要时刻盯着备份文件会占用不少空间空间满了备份任务必挂。6.3 异地备份与云备份的补充本地磁盘备份再完整一旦机房整体故障火灾、断电、勒索病毒本地数据也保不住。所以备份文件一定要做异地副本。最简单的方案是用SQL Agent作业在备份完成后执行一个copy命令把文件传到另一台服务器或NAS上。有条件的话直接接云厂商的对象存储比如OSS、COS、S3把备份文件自动同步上云。至于具体选哪家要根据你所在环境和合规要求来但原则只有一个备份文件不能只留在本机。6.4 最后分享一个小技巧在真实项目里我吃过多次亏之后终于养成了一个习惯每个数据库备份脚本里都加上CHECKSUM每个重要备份完成后都执行一次RESTORE VERIFYONLY并且每个季度挑一个库做一次实打实的还原演练。别嫌麻烦这套“备份验证演练”的组合比任何高可用方案都让人踏实。说到底SQL Server数据库的备份和还原并不复杂难的是你能不能坚持把每一步都做扎实、做规范。希望这篇教程能帮你少走些弯路关键时刻派上用场。
返回列表