码迷,mamicode.com
首页 > 其他好文 > 详细

第十七周翻译

时间:2018-01-13 14:27:52      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:arch   文件路径   频繁   文件的操作   业务   相同   状态   命令执行   after   

楼梯在SQL Server事务日志管理,5:管理登录完整恢复模式

通过托尼?戴维斯,2012/01/27

该系列

本文是楼梯系列的一部分:楼梯在SQL Server事务日志管理

当一切都很顺利,没有需要特别意识到什么事务日志或它是如何工作的。 你只需要相信,每个数据库都有正确的备份机制。 当事情出错时,事务日志的理解是非常重要的采取纠正行动,特别是在一个时间点恢复的数据库是必需的,紧急! 托尼·戴维斯给正确的细节层次,每一个DBA应该知道。

在这个层次,我们将回顾为什么以及如何把在工作日志备份FULL恢复模式,以及如何使用这些日志备份文件执行数据库恢复,与一个完整的数据库备份。FULL恢复模式支持数据库恢复内任何时候一个可用的日志备份和,假设尾日志备份,直到最后提交的事务的时候,在故障发生之前。

什么记录?

FULL复苏模式,所有操作都记录下来。 为INSERT,UPDATEDELETE操作,这意味着对于修改的每一行,将会有一个日志记录描述的ID执行语句的事务,事务开始和结束时,哪些页面被改变,数据变化,等等。

可以最低限度的操作记录SELECT INTO,BULK INSERTCREATE INDEX在工作时,仍然完全记录的FULL恢复模式,但略有不同。 行受这些操作不是单独记录; 而不是只有数据库页记录,因为他们得到了。 这减少了日志听到这样的操作,确保所有仍然存在相同的信息存在,需要执行回滚,重做,时间点恢复。 Kalen德莱尼发表了一些调查记录SELECT INTO(http://sqlblog.com/blogs/kalen_delaney/archive/2011/03/15/what-gets-logged-for-select-into.aspx)和索引重建(http://sqlblog.com/blogs/kalen_delaney/archive/2011/03/08/what-gets-logged-for-index-rebuilds.aspx)操作,无论是FULLBULK_LOGGED恢复模式。 minimally-logged操作的日志记录的差异,当在工作BULK_LOGGED模式,将更详细地讨论6- - - - - -管理登录 批量记录 恢复模式。

为什么备份事务日志吗?

FULL恢复模式,只有一个日志备份可以导致截断日志。 因此,事务日志将全面和完整的交易记录执行自上一次事务日志备份。 因为所有操作是完全记录,日志文件可以长很大,很快,在繁忙的系统。

因此,当在工作FULL复苏模式,它是 至关重要的你执行常规事务日志备份可选地,除了完整备份和差异备份。 许多新手或兼职dba执行一次完整备份数据库,但是他们没有执行事务日志备份。 结果,不截断事务日志,它在不断的增长,直到驱动是耗尽了磁盘空间,导致SQL服务器停止工作。

截断日志就会发生日志备份,假设一个检查点之前的备份以来发生了,没有其他因素拖延截断,如数据备份或恢复操作。 完整列表的因素,可能会推迟恢复的甚低频截断,以及因素保持日志活跃的大片地区,否则不会需要,如一个流氓,长期未提交的事务或数据库镜像或复制过程,看到的:http://msdn.microsoft.com/en-gb/library/ms345414.aspx

COPY_ONLY事务日志备份

COPY_ONLY备份事务日志不截断事务日志。 一个COPY_ONLY日志备份的独立正常日志备份方案; 它不会打破日志备份链。

简而言之,事务日志备份执行的双重目的允许恢复和恢复到前一个时间点,以及控制事务日志的大小。 最常见的原因在事务log-related问题FULL恢复模式和不带日志备份,或者不够经常把日志备份控制事务日志文件的大小。

如果你不确定是否被在一个给定的事务日志备份数据库,然后你可以简单的询问backupset表中MSDB查询数据库,使用一个类似于清单5.1所示。

使用msdb;选择backup_set_id,backup_start_date,backup_finish_date,backup_size,recovery_model,

         (类型]dbobackupset在哪里database_name= “TestDB”

清单5.1:日志备份被吗?

type,D表示一个数据库备份,L一个日志备份和I一个微分备份。

请注意,由于数据backupset表可以操纵而不会影响备份和恢复的行为,你可能想要验证你的发现从这个查询,通过查询sys.database_recovery_status看到的价值last_log_backup_lsn3.5(见清单),sys.databases表的价值log_reuse_wait_desc(将返回LOG_BACKUP如果需要一个备份)

如何备份事务日志

正如前面所讨论的那样,不可能执行一个事务日志备份不先把至少一个完整的备份。 事实上,如果你有一个数据库FULL复苏模式,但从来没有备份,那么它不会工作FULL恢复模式。 数据库将在auto-truncate模式直到第一次执行完整备份。

所有数据库备份、完全、日志或否则,执行使用BACKUP命令。 命令接受大量的选项,这里记录:http://msdn.microsoft.com/en-us/library/ms186865.aspx 然而,在最基本的,通常它是如何使用,命令执行完整备份到磁盘如下:

BACKUP DATABASE DatabaseNameTO DISK =‘FileLocation\DatabaseName.bak‘;

如果这是第一次执行备份,DatabaseName.bak文件将被创建在指定的目录中。 如果这些文件已经存在,那么默认行为是追加后续备份该文件。 覆盖此行为,规定任何应该覆盖现有的文件,我们可以使用INIT选项,如下:

BACKUP DATABASE DatabaseNameTO DISK =‘FileLocation\DatabaseName.bak‘WITH INIT;

最常见的,然而,每个后续备份是给予一个唯一的名称; 在即将到来的这个部分,恢复到故障点。

每次定期(如每日)完整备份后,将会有频繁的(如每小时)日志备份,非常相似的基本命令:

BACKUP LOG DatabaseNameTO DISK =‘FileLocation\DatabaseName_Log.bak‘;

存储日志备份

显然备份数据和日志文件不应存储在相同的驱动器上,主持人现场文件。 如果驱动硬件故障那么你所有的副本将丢失以及现场文件,备份将白费。 文件应该备份到一个单独的设备,或备份到本地镜像驱动器。

日志备份的频率

正如先前的水平,你可能会把日志备份每15分钟,甚至更频繁。 在这种情况下,为了避免需要恢复大量的事务日志文件,您可以选择采用一个备份计划组成的完整备份穿插微分备份,点缀着事务日志备份。

在现实中,备份方案往往是更多的理想和实际之间的妥协,评估之间的真实数据丢失的风险,它将花费公司,所涉及的成本降低这种风险。 许多非常重要的业务应用程序使用稍微简单些,但是严谨、备份计划,也许涉及定期夜间完整备份加上每小时的事务日志备份。

日志备份的频率也可能由数据库的事务数量。 数据库很忙,可能需要经常备份为了控制日志的大小。

没有简单的方法来计算频率日志备份。 大多数dba将他们最好的估计应采取多长时间日志备份,然后观察生长特性文件,然后调整备份方案的必要阻止他们获得超大号的。

日志链以及如何打破它

如上所述,不可能执行一个事务日志备份不先把至少一个完整的备份。 为了恢复一个数据库的时间点,要么结束的一个特定的日志备份或时间点在一个特定的日志备份,一定存在一个完整的日志记录,从第一个日志备份后,一个完整的(或微分备份),直到故障点。 这是众所周知的日志链

有很多方法可以打破日志链,如果这意味着你只能恢复数据库日志备份的时间事件发生之前,打破了链。 简而言之,破坏链一个好主意如果你关心的能力来恢复您的数据。 两种最常见的方式打破链包括:

  • 损失或腐败的事务日志备份文件——你只能恢复到之前的最后好日志备份。 日志链将重新开始下一个完整或微分备份好。
  • 切换到 SIMPLE 恢复模式——如果你开关FULLSIMPLE恢复模式,这将打破日志链作为一个检查点会煽动,可以立即截断事务日志。 如果你返回的时候出现FULL模式,你需要再重新启动完整备份日志链。 事实上,直到你完全备份,数据库将继续留在auto-truncate模式,你将无法备份日志文件。

Pre-SQL Server 2008,有几个命令,BACKUP LOG WITH NO_LOGBACKUP LOG WITH TRUNCATE_ONLY(他们在功能上是等同的),发布时,将迫使一个日志文件截断所以打破日志链。 你不应该发出这些命令在任何版本的SQL服务器,但我在这里提及他们,因为他们仍然由粗心的习惯,在处理失控的日志文件”,没有理解的意义的能力来恢复他们的数据库。 看到水平8 -帮助,我的日志已满为更多的细节。

尾日志备份

只要你有最近一次完全备份,一个完整的日志链,你可以恢复你的数据库的状态存在的前的最后一个日志备份任何失败。 然而,假设你把事务日志备份每小时,小时,1:45PM发生故障。 你可能会失去价值45分钟的数据; 事实上,如果失败是如此灾难性生活事务日志是无法挽回,那么你将失去的数据量。

然而,有时可用的生活事务日志仍然可以即使数据文件没有,特别是如果包含在一个单独的事务日志,专用的驱动器。 如果是这种情况,你应该现场事务日志备份即执行最后一个备份自上次生成的日志记录日志备份。 这将捕捉剩下的实时日志文件中的日志记录,故障点。 这被称为一个尾日志备份和是最后的行动开始之前,应该进行恢复和恢复操作。

尾日志备份和minimally-logged操作

如果数据文件是不可用的数据库失败,和尾巴的日志包含最小记录操作,那么它将不可能做一个尾日志备份,因为这将需要访问数据文件的更改的数据区段。 这将更详细地介绍6管理 散装事务日志记录模式。

如果你想恢复在线数据库,然后尾日志备份的如下:

BACKUP LOG DatabaseNameTO DISK =‘FileLocation\DatabaseName_Log.bak‘WITH NORECOVERY

NORECOVERY选择把数据库恢复状态,假设您希望执行下一个动作是一个RESTORE 如果数据库是离线,不会开始,你仍然应该尝试备份日志的尾巴刚刚描述(虽然NORECOVERY选项可以省略,因为没有事务将在进步)

如果你确保日志文件受损,文档表明,作为最后的手段,你试着做一个尾日志备份:

BACKUP LOG DatabaseNameTO DISK =‘FileLocation\DatabaseName_Log.bak‘WITH CONTINUE_AFTER_ERROR

如果主数据库和数据文件损坏了,但可用的日志,微软建议重建主数据库,然后最后一个活动日志备份 然而,这些主题范围外的楼梯,我引用你的文档进一步的细节。 看到http://msdn.microsoft.com/en-us/library/ms190952.aspx

执行恢复和恢复

在执行一个尾日志备份,如果可能的话,下一步是恢复上次完全备份(其次是微分备份,如果合适的话),然后恢复日志备份文件的完整序列,包括尾日志备份。 这个恢复操作序列的基本语法如下:

RESTORE {DATABASE | LOG} DatabaseNameFROM DISK =‘FileLocation\FileName.bak‘WITH NORECOVERY;

如果你什么时候恢复省略了WITH NORECOVERY选项,然后在默认情况下RESTORE命令将继续WITH RECOVERY 换句话说,SQL Server将试图调和数据和日志文件,前滚完成交易,然后回滚事务未完成。 通过指定WITH NORECOVERY我们指示SQL Server,我们正在进入一个恢复序列和更多的操作必须向前滚,可以执行任何回滚之前。 在恢复序列恢复上次备份后,数据库可以恢复如下:

RESTORE DATABASE DatabaseName WITH RECOVERY

一个常见需求是将数据库恢复到一个不同的位置,在这种情况下,您可以简单地将文件恢复过程的一部分,这里所描述的那样:http://msdn.microsoft.com/en-us/library/ms190255.aspx

数据库故障后恢复

下面的例子描述了如何恢复一个数据库失败,即不再可访问的数据库数据文件。

完全恢复到故障点

假设事务日志后可以达到数据库失败,也许由硬件故障引起的,然后在理论上应该可以恢复和恢复数据库到故障点,通过以下步骤:

  1. 备份日志的尾部
  2. 恢复最近的全备份(如果适用)+微分,
  3. 反过来,恢复每一个事务日志备份后被完全(或微分)备份和失败的时间之前完成
  4. 恢复尾日志备份
  5. 恢复数据库

许多例子上发现书在线演示恢复和恢复从一个备份”,换句话说,一个装置”,所有备份存储。 实际上,这意味着,当备份到磁盘,备份设备是一个.bak磁盘上的某个位置的文件。

例如,清单5.2中所示的简单示例使用一个备份组组成的一个完整备份,一个事务日志备份,并展示了如何执行一个完整的恢复。 为了运行此代码,您首先需要重新创建TestDB数据库,然后插入几行数据样本(为方便起见,脚本,CreateAndPopulateTestDB.sql,包含在代码下载这个水平)。 你还需要在本地创建一个备份目录C:驱动你的数据库服务器,或修改文件路径。

——执行一个测试数据库的完整备份——与格式选项启动一个新的备份集——小心,因为它会覆盖任何现有集——完整备份成为第一个文件集备份 数据库TestDB 磁盘 = “C:\ \ TestDB.bak备份格式;——执行一个测试数据库的事务日志备份——这是第二个文件的集合备份 日志TestDB 磁盘 = “C:\ \ TestDB.bak备份——.... <这里故障> ....

——恢复HEADERONLY命令是可选的。——它只是证实文件组成——当前的设置恢复HEADERONLY 磁盘 = “C:\ \ TestDB.bak备份——备份日志的尾巴准备恢复——这将成为第三bakup集的文件备份 日志TestDB 磁盘 = “C:\ \ TestDB.bak备份NORECOVERY;——恢复完全备份恢复 数据库TestDB 磁盘 = “C:\ \ TestDB.bak备份 文件=1,NORECOVERY;

——应用事务日志备份恢复 日志TestDB 磁盘 = “C:\ \ TestDB.bak备份 文件=2,NORECOVERY;

——应用尾日志备份恢复 日志TestDB 磁盘 = “C:\ \ TestDB.bak备份 文件=3,NORECOVERY;

——恢复数据库恢复 数据库TestDB复苏;

清单5.2:备份和恢复,备份集; 不推荐

然而,使用备份集似乎是一个遗物的时候,数据库备份到磁带。 当备份到磁盘,使用这个方案是一个坏主意,因为当然,备份文件将很快成长很大。

在实践中,它是更常见的,每个完整备份和事务日志备份文件将单独命名,而且可能印有备份的时间和日期。 例如,大多数第三方备份工具,流行从用户社区收集脚本,加上维护计划向导在ssm /设计师,都如创建单独的日期戳的文件。AdventureWorks_FULL_20080904_000001.bak

因此,一个更常见的备份和恢复计划将使用惟一命名备份,如清单5.3所示。

使用;备份 数据库TestDB 磁盘 =“C:\ \ TestDB.bak备份初始化;——执行一个测试数据库的事务日志备份备份 日志TestDB 磁盘 =“C:\ \ TestDB_log.bak备份初始化;——.... <这里故障> ....

——备份日志的尾巴准备恢复备份 日志TestDB 磁盘 =“C:\ \ TestDB_taillog.bak备份NORECOVERY,初始化;——恢复完全备份恢复 数据库TestDB 磁盘 = “C:\ \ TestDB.bak备份NORECOVERY;

——应用事务日志备份恢复 日志TestDB 磁盘 = “C:\ \ TestDB_log.bak备份NORECOVERY;

——应用尾日志备份恢复 日志TestDB 磁盘 = “C:\ \ TestDB_taillog.bak备份NORECOVERY;

——恢复数据库恢复 数据库TestDB复苏;

清单5.3:备份,备份和恢复,惟一命名的文件

去年好日志备份时间点恢复

有时,不幸的是,它可能不可能执行一个完整的恢复; 例如,如果现场事务日志不可用的结果失败。 在这种情况下,我们需要恢复的最新日志备份。 这是需要准备这个可能性即包含事务日志失败的驱动器,这规定多长时间日志备份。 如果你把备份每15分钟,那么你暴露15分钟数据丢失的风险。

想象我们的顺序执行备份,如清单5.4所示。 为了演示,我们覆盖之前的备份文件,备份序列明显缩短要比在现实。

——完整的备份在凌晨2使用;备份 数据库TestDB 磁盘 = “C:\ \ TestDB.bak备份初始化;——日志备份1 2.15使用;备份 日志TestDB 磁盘 = “C:\ \ TestDB_log.bak备份初始化;——日志备份2 2.30使用;备份 日志TestDB 磁盘 = “C:\ \ TestDB_log2.bak备份初始化;

清单5.4:短系列日志备份

如果发生灾难性故障发生后不久,两点半,我们可能需要将数据库恢复到结束时其存在状态日志备份2,21日凌晨230分。

恢复序列在这样的一个例子非常类似于我们之前看到的,在清单5.3,但由于尾巴备份是不可能的,我们只能恢复到某种程度,我们需要使用STOPAT选项,如清单5.5所示。

——恢复完全备份恢复 数据库TestDB 磁盘 = “C:\ \ TestDB.bak备份NORECOVERY;

,恢复日志文件1恢复 日志TestDB 磁盘 = “C:\ \ TestDB_log.bak备份NORECOVERY,STOPAT= “202011日上午12:00;

——恢复日志文件2恢复 日志TestDB 磁盘 = “C:\ \ TestDB_Log2.bak备份NORECOVERY,STOPAT= “202011日上午12:00;

——恢复数据库恢复 数据库TestDB复苏;

清单5.5:恢复时间点,使用STOPAT

因为我们已经指定了STOPAT在未来,这段代码将滚所有完成交易的最后第二个事务日志。

另外,可以指定一个STOPAT跌倒的时候,时间范围内的交易记录在特定的日志文件中。 在这种情况下,数据库将恢复到最后一次提交事务时指定。 这是非常有用的,当你知道你想要什么时间来恢复,但不知道什么日志备份包含。

还可以恢复到一个特定的事务。 这是有用的,例如,你需要恢复多个数据库,访问某些应用程序中,一个逻辑一致的观点。 这里没有进一步讨论这个话题,但是你可以找到更多的书在线(http://msdn.microsoft.com/en-us/library/ms187014.aspx),Prajdic提供了一个很好的例子:http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx

“坏交易”后恢复

以外的任何数据库失败的环境中,可能需要恢复数据库备份,加上事务日志,以返回一个数据库一个特定的时间点就在一个错误的数据修改,删除或删除一个表。

你对这种情况将取决于问题的性质。 如果可能的话,你可能会从数据库断开所有用户(通知),和评估的影响刚刚发生了什么事。 在某些情况下,您可能需要估计问题发生的时间,然后做一个全面复苏的数据库和日志使用时间点恢复。 恢复完成后,你必须通知用户,一些交易可能已经丢失,并请求原谅。

当然,你经常会无法中断正常的经营以这种方式,来解决意外数据丢失。 自住数据库仍然是启动和运行和访问,你可以试着恢复备份的数据库STANDBY模式。 这允许进一步的日志备份恢复但不像当使用NORECOVERY,数据库仍然是可读的。 恢复计划可能会看起来像这样:

  1. 恢复备份的数据库,STANDBY模式,与现场数据库
  2. 日志前滚到坏交易发生之前,和数据丢失。
  3. 将丢失的数据复制到实时数据库将恢复副本

当然,这个过程不一定是简单的,这可能非常耗时。 除非你购买专门的日志阅读工具,可以直接查询日志备份,向前滚动日志可以是一系列的步骤包括恢复日志,检查数据,进一步恢复一点,等等,直到你糟糕的交易发生的确切位置。 第三步是很困难的,因为你将数据引入系统不一定符合数据库的当前状态,所以可以参照完整性的问题。

让我们看看一个例子实现上面的步骤12。 首先,让我们从头重新开始运行CreateAndPopulateTestDB.sql脚本重新创建TestDB数据库,10行测试数据插入一个新的LogTest表。 在清单5.6,我们只是做一个完整的数据库备份(覆盖任何以前的备份文件)。 您需要创建备份目录,如果你没有这么做,或适当的调整路径。

——数据库的完整备份备份 数据库TestDB 磁盘 =“C:\ \ TestDB.bak备份初始化;

清单5.6:完整的备份TestDB

然后,我们的数据插入一个新行LogTest表。

使用TestDB

插入  (TestDB]dbo]LogTest]

           ([SomeInt]

           ,(SomeLetters2])

     

           (66666,

           “)

           选择*dboLogTest

清单5.7:一个11行插入TestDB

现在我们有了一个生活TestDB数据库中有11个行LogTest表和备份版本10行。 现在让我们捕捉额外的修改日志备份,如清单5.8所示。

使用

备份 日志TestDB 磁盘 =“C:\ \ TestDB_log.bak备份初始化;

清单5.8:一个日志备份TestDB

现在,我们要模拟一个错误坏交易”,简单地放弃LogTest表后,我们做最后一个日志备份。

使用TestDB

下降 dboLogTest;

使用

备份 日志TestDB 磁盘 =“C:\ \ TestDB_log2.bak备份初始化;

清单5.9:灾难!

为了尝试检索数据丢失,而不中断正常的经营,我们将恢复的一个副本TestDB数据库中STANDBY模式。 备用数据库的数据和日志文件ANewTestDB,搬到备用目录(你需要创建这个目录之前)

恢复到TestDB数据库的一个副本,调用——ANewTestDB,在待机模式使用;恢复 数据库ANewTestDB 磁盘 =“C:\ \ TestDB.bak备份

   备用=“C:\ \ ANEWTestDB.bak备份,移动“TestDB_dat”  “C:\备用\ ANewTestDB.mdf”,移动“TestDB_log”  “C:\备用\ ANewTestDB.ldf”

清单5.10:恢复的一个副本TestDBSTANDBY模式

我们现在有一个新的数据库,调用ANewTestDB,这是在备用/只读模式,如图5.1所示。

 

5.1:备用数据库

一个查询LogTest表中ANewTestDB数据库将显示10行。 然而,我们想要表回状态在前它被错误地下降。 因此,下一步是执行恢复日志备份到备用数据库。

使用

恢复 日志ANewTestDB 磁盘 = “C:\ \ TestDB_log.bak备份

   备用=“C:\ \ ANewTestDB_log.bak备份

清单5.11:恢复日志备份ANewTestDB数据库,STANDBY模式

在这一点上,一个查询ANewTestDB揭示了11,我们现在可以准备,数据复制到现场数据库。 如果我们更进一步和恢复第二日志备份,我们意识到我们已经走得太远,表会失踪在备用数据库。

另一个做备用恢复是考虑使用第三方工具,比如红门SQL虚拟恢复备份是山,它提供了一种生活方式,功能齐全的数据库,没有身体的恢复。

是否dba喜欢与否,开发人员经常做访问生产数据库执行临时数据加载和变化。 是DBA和开发人员的共同责任,以确保顺利进行,因此不会造成问题,要求刚刚描述的行动。 晚些时候我们回到这个话题6——处理批量操作

当然,修复行动所需的确切性质取决于坏交易的性质。 如果一个表是意外下降那么很有可能你会走的RESTORE WITH STANDBY路线。 在其他时候,你可能会侥幸简单的创建一个反向流氓修改脚本。

如果破坏只影响一个列或有限数量的行,那么它可能,作为一种替代方法,使用一个工具,比如SQL数据比较,可以比较直接备份文件,可以做行级恢复。

或者,如果您运行SQL Server 2005企业版(或更高版本),并提供最近的数据库快照,您可以运行一个查询检索数据的快照,因为它看起来当时数据库快照,然后写一个UPDATEINSERT命令将数据从数据库快照进入生活,源数据库。

最后,作为最后的手段,专业读者日志工具可能帮助你扭转的影响事务虽然我不知道有任何在SQL Server 2005,后来可靠地工作。

总结

在这个层面上,我们已经介绍了基础知识数据库备份和恢复日志文件的操作FULL恢复模式,这为许多生产数据库将成为常态。

对于大多数dba来说,需要执行时间点恢复是一种罕见的事件,但它是其中的一个任务,如果它是必要的,它绝对是至关重要的是做,做得很好; DBA的声誉取决于它。

对于腐败,驱动器故障,等等,时间点恢复可能涉及,如果幸运的话,备份事务日志的尾巴和恢复故障点。 如果事务日志不可用,或者你恢复为了恢复时间点发生了坏交易之前,那么情况就变得比较复杂,但是希望的一些技术覆盖在这一步会有所帮助。

 

第十七周翻译

标签:arch   文件路径   频繁   文件的操作   业务   相同   状态   命令执行   after   

原文地址:https://www.cnblogs.com/hhhhhhh/p/8278863.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!