recover 的再一次理解

本文通过实战演示了如何使用 Oracle RMAN 工具进行完整恢复操作,包括数据文件的验证、恢复及数据库重启过程。介绍了在遇到数据文件损坏情况时,利用备份文件进行数据恢复的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C:\Documents and Settings\Administrator>sqlplus /nolog

 

SQL*Plus: Release 10.2.0.1.0 - Production on 星期六 6 14 15:29:05 2008

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

 

15:29:05 idle>conn /as sysdba

已连接。

15:29:11 sys@LEE>desc test_recover

 名称                                                                                是否为空? 类型

 ----------------------------------------------------------------------------------- -------- ------

--------------------------------------------------

 ID                                                                                           NUMBER

(38)

 

15:29:17 sys@LEE>select *from test_recover;

 

        ID

----------

         1

         2

         3

        31

        32

        33

 

已选择6行。

// 原表~~~~~~~没有用rman 做备份

已用时间:  00: 00: 00.11

15:29:25 sys@LEE>shutdown immediate

数据库已经关闭。

已经卸载数据库。

ORACLE 例程已经关闭。

 

//  删除 表空间sping O1_MF_SPRING_44QPLLLK_.DBF 文件

15:31:03 sys@LEE>startup force

ORA-32004: obsolete and/or deprecated parameter(s) specified

ORACLE 例程已经启动。

 

Total System Global Area  440401920 bytes

Fixed Size                  1249440 bytes

Variable Size             113250144 bytes

Database Buffers          318767104 bytes

Redo Buffers                7135232 bytes

数据库装载完毕。

ORA-01157: 无法标识/锁定数据文件 6 - 请参阅 DBWR 跟踪文件

ORA-01110: 数据文件 6: 'E:\TEST_DEST\LEE\DATAFILE\O1_MF_SPRING_44QPLLLK_.DBF'

 

 

15:31:43 sys@LEE>exit

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production

With the Partitioning, OLAP and Data Mining options 断开

 

C:\Documents and Settings\Administrator>rman

 

恢复管理器: Release 10.2.0.1.0 - Production on 星期六 6 14 15:31:48 2008

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

 

RMAN> connect target/

 

已连接到目标数据库: LEE (DBID=490429669, 未打开)

 

RMAN> report schema;

 

使用目标数据库控制文件替代恢复目录

数据库方案报表

 

永久数据文件列表

===========================

文件大小 (MB) 表空间           回退段数据文件名称

---- -------- -------------------- ------- ------------------------

1    800      SYSTEM               ***     E:\ORACLE\PRODUCT\10.2.0\ORADATA\LEE\SYSTEM01.DBF

2    35       UNDOTBS1             ***     E:\ORACLE\PRODUCT\10.2.0\ORADATA\LEE\UNDOTBS01.DBF

3    600      SYSAUX               ***     E:\ORACLE\PRODUCT\10.2.0\ORADATA\LEE\SYSAUX01.DBF

4    1500     USERS                ***     E:\ORACLE\PRODUCT\10.2.0\ORADATA\LEE\USERS01.DBF

5    100      EXAMPLE              ***     E:\ORACLE\PRODUCT\10.2.0\ORADATA\LEE\EXAMPLE01.DBF

6    0        SPRING               ***     E:\TEST_DEST\LEE\DATAFILE\O1_MF_SPRING_44QPLLLK_.DBF

7    300      TEST_DATA_16K        ***     E:\TEST_DEST\LEE\DATAFILE\TEST_DATA_16K.DBF

 

临时文件列表

=======================

文件大小 (MB) 表空间           最大大小 (MB) 临时文件名称

---- -------- -------------------- ----------- --------------------

1    106      TEMP                 32767       E:\ORACLE\PRODUCT\10.2.0\ORADATA\LEE\TEMP01.DBF

 

RMAN> restore datafile 6 validate;

 

启动 restore 14-6 -08

分配的通道: ORA_DISK_1

通道 ORA_DISK_1: sid=155 devtype=DISK

 

通道 ORA_DISK_1: 正在启动数据文件备份集验证

通道 ORA_DISK_1: 正在读取备份段 E:\BACKUP\LEE\LEE_BACK_0HJIMGOD_1_1

通道 ORA_DISK_1: 已恢复备份段 1

段句柄 = E:\BACKUP\LEE\LEE_BACK_0HJIMGOD_1_1 标记 = FULL_LEE

通道 ORA_DISK_1: 验证完成, 用时: 00:00:36

完成 restore 14-6 -08

 

RMAN> recover datafile 6;

 

启动 recover 14-6 -08

使用通道 ORA_DISK_1

// 不能recover

RMAN-03002: recover 命令 ( 06/14/2008 15:34:49 ) 失败

RMAN-06094: 数据文件6必须重新存储

 

 

 

RMAN> restore datafile 6;

 

启动 restore 14-6 -08

使用通道 ORA_DISK_1

 

通道 ORA_DISK_1: 正在开始恢复数据文件备份集

通道 ORA_DISK_1: 正在指定从备份集恢复的数据文件

正将数据文件00006恢复到E:\TEST_DEST\LEE\DATAFILE\O1_MF_SPRING_44QPLLLK_.DBF

通道 ORA_DISK_1: 正在读取备份段 E:\BACKUP\LEE\LEE_BACK_0HJIMGOD_1_1

通道 ORA_DISK_1: 已恢复备份段 1

段句柄 = E:\BACKUP\LEE\LEE_BACK_0HJIMGOD_1_1 标记 = FULL_LEE

通道 ORA_DISK_1: 恢复完成, 用时: 00:04:08

完成 restore 14-6 -08

 

RMAN> recover datafile 6;

 

启动 recover 14-6 -08

使用通道 ORA_DISK_1

 

正在开始介质的恢复

 

存档日志线程 1 序列 54 已作为文件 E:\ARCHIVE\ARCHIVE_1\ARC00054_0655762857.001 存在于磁盘上

存档日志线程 1 序列 55 已作为文件 E:\ARCHIVE\ARCHIVE_1\ARC00055_0655762857.001 存在于磁盘上

存档日志线程 1 序列 56 已作为文件 E:\ARCHIVE\ARCHIVE_1\ARC00056_0655762857.001 存在于磁盘上

存档日志线程 1 序列 57 已作为文件 E:\ARCHIVE\ARCHIVE_1\ARC00057_0655762857.001 存在于磁盘上

存档日志线程 1 序列 58 已作为文件 E:\ARCHIVE\ARC00058_0655762857.001 存在于磁盘上

存档日志线程 1 序列 59 已作为文件 E:\ARCHIVE\ARC00059_0655762857.001 存在于磁盘上

存档日志线程 1 序列 60 已作为文件 E:\ARCHIVE\ARC00060_0655762857.001 存在于磁盘上

存档日志线程 1 序列 1 已作为文件 E:\ARCHIVE\ARC00001_0657239997.001 存在于磁盘上

存档日志线程 1 序列 2 已作为文件 E:\ARCHIVE\ARC00002_0657239997.001 存在于磁盘上

存档日志线程 1 序列 1 已作为文件 E:\ARCHIVE\ARC00001_0657281613.001 存在于磁盘上

存档日志线程 1 序列 1 已作为文件 E:\ARCHIVE\ARC00001_0657282439.001 存在于磁盘上

存档日志线程 1 序列 1 已作为文件 E:\ARCHIVE\ARC00001_0657324733.001 存在于磁盘上

存档日志线程 1 序列 2 已作为文件 E:\ARCHIVE\ARC00002_0657324733.001 存在于磁盘上

存档日志线程 1 序列 3 已作为文件 E:\ARCHIVE\ARC00003_0657324733.001 存在于磁盘上

存档日志文件名 =E:\ARCHIVE\ARCHIVE_1\ARC00054_0655762857.001 线程 =1 序列 =54

存档日志文件名 =E:\ARCHIVE\ARCHIVE_1\ARC00055_0655762857.001 线程 =1 序列 =55

存档日志文件名 =E:\ARCHIVE\ARCHIVE_1\ARC00056_0655762857.001 线程 =1 序列 =56

存档日志文件名 =E:\ARCHIVE\ARCHIVE_1\ARC00057_0655762857.001 线程 =1 序列 =57

存档日志文件名 =E:\ARCHIVE\ARC00058_0655762857.001 线程 =1 序列 =58

存档日志文件名 =E:\ARCHIVE\ARC00059_0655762857.001 线程 =1 序列 =59

存档日志文件名 =E:\ARCHIVE\ARC00060_0655762857.001 线程 =1 序列 =60

存档日志文件名 =E:\ARCHIVE\ARC00001_0657239997.001 线程 =1 序列 =1

存档日志文件名 =E:\ARCHIVE\ARC00002_0657239997.001 线程 =1 序列 =2

存档日志文件名 =E:\ARCHIVE\ARC00001_0657281613.001 线程 =1 序列 =1

存档日志文件名 =E:\ARCHIVE\ARC00001_0657282439.001 线程 =1 序列 =1

// recover 失败~~~~~~~~~~~~~·

RMAN-03002: recover 命令 ( 06/14/2008 15:39:31 ) 失败

ORA-00283: recovery session canceled due to errors

RMAN-11003: 在分析/执行 SQL 语句期间失败: alter database recover logfile 'E:\ARCHIVE\ARC00001_065728

2439.001'

ORA-00283: 恢复会话因错误而取消

ORA-00600: 内部错误代码, 参数: [krhpfh_03-1209], [6], [657324733], [657327569], [41291533], [0], [0]

, [0]

ORA-01110: 数据文件 6: 'E:\TEST_DEST\LEE\DATAFILE\O1_MF_SPRING_456X57DP_.DBF'

 

 

//  再来一次!!!

RMAN> recover datafile 6;

 

启动 recover 14-6 -08

使用通道 ORA_DISK_1

 

正在开始介质的恢复

介质恢复完成, 用时: 00:00:03

 

完成 recover 14-6 -08

 

RMAN> alter database open;

 

数据库已打开

 

RMAN> exit

 

 

恢复管理器完成。

 

C:\Documents and Settings\Administrator>sqlplus /nolog

 

SQL*Plus: Release 10.2.0.1.0 - Production on 星期六 6 14 15:40:48 2008

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

 

15:40:48 idle>conn /as sysdba

已连接。

15:40:52 sys@LEE>select * from test_recover;

//  恢复成功

        ID

----------

         1

         2

         3

        31

        32

        33

 

已选择6行。

 

已用时间:  00: 00: 00.11

15:41:03 sys@LEE>

 

 

小结 可见 rman做恢复recover的时候是利用重做日志或增量备份来重建丢失的数据

 

 

 

文档解析:

 

Complete Recovery

 

Complete recovery involves using redo data or incremental backups combined with a backup of a database, tablespace, or datafile to update it to the most current point in time. It is called complete because Oracle applies all of the redo changes contained in the archived and online logs to the backup. Typically, you perform. complete media recovery after a media failure damages datafiles or the control file.

 

You can perform. complete recovery on a database, tablespace, or datafile. If you are performing complete recovery on the whole database, then you must:

 

    *

 

      Mount the database

    *

 

      Ensure that all datafiles you want to recover are online

    *

 

      Restore a backup of the whole database or the files you want to recover

    *

 

      Apply online or archived redo logs, or a combination of the two

 

If you are performing complete recovery on a tablespace or datafile, then you must:

 

    *

 

      Take the tablespace or datafile to be recovered offline if the database is open

    *

 

      Restore a backup of the datafiles you want to recover

    *

 

      Apply online or archived redo logs, or a combination of the two

 

 

Incomplete Recovery

 

Incomplete recovery, or point-in-time recovery, uses a backup to produce a noncurrent version of the database. In other words, you do not apply all of the redo records generated after the most recent backup. You usually perform. incomplete recovery of the whole database in the following situations:

 

    *

 

      Media failure destroys some or all of the online redo logs.

    *

 

      A user error causes data loss, for example, a user inadvertently drops a table.

    *

 

      You cannot perform. complete recovery because an archived redo log is missing.

    *

 

      You lose your current control file and must use a backup control file to open the database.

 

To perform. incomplete media recovery, you must restore all datafiles from backups created prior to the time to which you want to recover and then open the database with the RESETLOGS option when recovery completes. The RESETLOGS operation creates a new incarnation of the database—in other words, a database with a new stream of log sequence numbers starting with log sequence 1.

 

Before using the OPEN RESETLOGS command to open the database in read/write mode after an incomplete recovery, it is a good idea to first open the database in read-only mode, and inspect the data to make sure that the database was recovered to the correct point. If the recovery was done to the wrong point, then it is easier to re-run the recovery if no OPEN RESETLOGS has been done. If you open the database read-only and discover that not enough recovery was done, then just run the recovery again to the desired time. If you discover that too much recovery was done, then you must restore the database again and re-run the recovery.

 

 

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/11134734/viewspace-346818/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/11134734/viewspace-346818/

<think>好的,我现在要帮用户写一个协程池的demo,并且重点是如何回收协程。首先,我得先理解协程池的基本概念。协程池的作用应该是管理多个协程,避免频繁创建和销毁带来的开销,所以需要复用协程。用户的问题核心在于回收,也就是当协程完成任务后,如何让它回到池子里等待下一个任务,而不是被销毁。 首先,我得回忆一下Go语言中协程的基本用法。通常用go关键字启动协程,但如何管理这些协程呢?可能需要用到channel来传递任务,同时控制协程的生命周期。协程池的结构应该包含任务队列、工作协程队列以及一些同步机制。 接下来,回收协程的关键点在于,当协程完成当前任务后,不能退出,而是继续等待新的任务。这可以通过一个循环来实现,让每个工作协程不断地从任务通道中读取任务,处理完后继续等待,而不是结束。这样协程就会一直存活,直到被显式关闭。 然后,如何优雅地关闭这些协程呢?可能需要一个信号channel,当关闭协程池的时候,发送关闭信号,所有工作协程接收到信号后退出循环,结束自身。同时,需要确保所有任务都处理完毕,或者有机制来终止正在执行的任务。 然后考虑任务的分发。主线程将任务发送到任务通道,工作协程从通道中获取任务并执行。任务通道应该是有缓冲的还是无缓冲的?如果有缓冲,可以限制任务队列的长度,避免内存问题。但用户示例可能需要简单的实现,可以先使用无缓冲,或者根据需求调整。 接下来,处理协程的回收。每个工作协程启动后,进入一个无限循环,等待任务。当任务到来时,处理任务,处理完后继续循环等待,而不是退出。这样协程就不会被回收,而是处于等待状态,实现复用。 可能还需要考虑panic的处理,避免某个任务导致整个协程池崩溃。每个工作协程应该有自己的recover机制,捕获panic,打印日志,然后继续运行,保持池子的稳定。 最后,如何测试这个协程池?可以创建几个任务,提交到池子中,观察是否被正确执行,以及协程数量是否保持稳定。使用sync.WaitGroup来等待所有任务完成,确保主线程不会提前退出。 总结步骤: 1. 定义协程池结构,包含任务通道、关闭信号通道、工作协程数量等。 2. 初始化协程池,启动指定数量的工作协程,每个协程循环等待任务。 3. 工作协程从任务通道读取任务,执行,处理panic,然后继续等待。 4. 提供提交任务的方法,将任务发送到任务通道。 5. 提供关闭协程池的方法,发送关闭信号,等待所有工作协程退出。 6. 处理任务通道的关闭,避免发送到已关闭的通道导致panic。 在实现过程中需要注意并发安全和通道的正确关闭,避免死锁和资源泄漏。比如,关闭任务通道时,确保没有更多的任务被提交,工作协程在通道关闭后可以退出循环。 现在,将这些思路转化为代码。可能需要使用sync.WaitGroup来跟踪工作协程的状态,确保关闭时所有协程都已退出。任务通道应该是一个chan,工作协程从中接收任务函数并执行。 测试的时候,可以提交多个任务,每个任务打印一些信息,然后观察协程是否被复用,以及关闭池子时是否所有协程都正确退出。</think>好的,下面是一个Go语言协程池的简单实现,包含协程回收机制。我将逐步解释关键设计: ```go package main import ( "context" "fmt" "sync" "time" ) // 协程池结构体 type GoroutinePool struct { taskChan chan func() // 任务通道 closeChan chan struct{} // 关闭信号 wg sync.WaitGroup // 等待组 poolSize int // 协程数量 } // 创建协程池 func NewGoroutinePool(size int) *GoroutinePool { pool := &GoroutinePool{ taskChan: make(chan func()), closeChan: make(chan struct{}), poolSize: size, } pool.start() return pool } // 启动工作协程 func (p *GoroutinePool) start() { p.wg.Add(p.poolSize) for i := 0; i < p.poolSize; i++ { go p.worker() } } // 工作协程主体 func (p *GoroutinePool) worker() { defer p.wg.Done() for { select { case task := <-p.taskChan: // 执行任务并处理panic func() { defer func() { if r := recover(); r != nil { fmt.Println("task panic:", r) } }() task() }() case <-p.closeChan: return // 收到关闭信号则退出 } } } // 提交任务 func (p *GoroutinePool) Submit(task func()) { select { case p.taskChan <- task: case <-p.closeChan: panic("pool already closed") } } // 优雅关闭协程池 func (p *GoroutinePool) Shutdown() { close(p.closeChan) p.wg.Wait() close(p.taskChan) } func main() { // 创建协程池(3个worker) pool := NewGoroutinePool(3) // 提交10个任务 for i := 0; i < 10; i++ { id := i pool.Submit(func() { time.Sleep(1 * time.Second) fmt.Printf("Task %d executed\n", id) }) } // 等待任务执行完毕 time.Sleep(2 * time.Second) // 关闭协程池 pool.Shutdown() fmt.Println("Pool shutdown complete") } ``` **关键设计解析**: 1. **协程复用机制**: ```go for { select { case task := <-p.taskChan: // 执行任务... case <-p.closeChan: return } } ``` 通过无限循环+通道监听,协程执行完任务后不会退出,而是继续等待新任务 2. **安全回收设计**: - `sync.WaitGroup` 跟踪所有worker状态 - 独立的关闭信号通道 `closeChan` - 执行 `Shutdown()` 时: ```go close(p.closeChan) // 发送关闭信号 p.wg.Wait() // 等待所有worker退出 ``` 3. **异常处理**: ```go defer func() { if r := recover(); r != nil { fmt.Println("task panic:", r) } }() ``` 每个任务都包裹异常捕获,避免单个任务panic导致整个worker崩溃 4. **任务提交保护**: ```go func (p *GoroutinePool) Submit(task func()) { select { case p.taskChan <- task: case <-p.closeChan: panic("pool already closed") } } ``` 防止向已关闭的池子提交任务 **执行流程**: 1. 创建包含3个worker的协程池 2. 提交10个任务到任务通道 3. worker持续从通道获取任务执行 4. 调用Shutdown()时: - 关闭closeChan通知所有worker - 等待所有worker安全退出 - 最后关闭任务通道 **协程回收的关键点**: 1. worker协程通过循环保持常驻,而非执行单任务 2. 通过通道通信实现任务调度,避免竞争条件 3. 关闭时先通知停止接收新任务,再等待现有任务完成 可以通过以下方式验证协程复用: ```go // 在main函数中添加 go func() { for { fmt.Printf("当前协程数: %d\n", runtime.NumGoroutine()) time.Sleep(500 * time.Millisecond) } }() ``` 观察输出可以看到协程数始终维持在预期数量(poolSize+2,主协程和监控协程)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值