转自:http://blog.csdn.net/mxzy55560593/article/details/7044749
chapter 2:启用事务
1:打开事务步骤
1:创建一个环境
2:打开环境时,DbEvn::open()指定DB_INIT_TXN;启用了事务系统默认也启用了日志系统;并且,如果你在创建环境的时候没有使用事务,以后就不能使用,因为创建时没有分配锁需要的结构
3:DbEvn::open()使用标志DB_INIT_MPOOL,初始化memory cache
4:初始化锁子系统,DbEvn::open()使用DB_INIT_LOCK
5:初始化日志系统:DbEvn::open()使用DB_INIT_LOG,默认是开启的,为了代码的可读性,建议显式设置
6:将所有数据库打开操作封装在事务中,但不需要显式的执行此步骤,打开数据库的时候指定上面的环境,你可以指定auto-commit
2:环境
1:基础
1:对于一个简单的应用,环境不是必须的,但如果要使用事务,环境是必须的,环境是多进程多线程使用数据库的基础,它为多进程多线程共享memory cache,locking table,log subsystem,文件命名空间提供支持
2::默认情况下,所有的数据库都以文件形式存储在磁盘上,事务所创建的log文件同样存储在磁盘上(你可以让它存储在share memory中),share-memory-regions存储在文件系统中,可以通过设置,使数据库和日志都保存在内存中
3:意识到所有应用程序共享一个数据库环境默认的相信彼此非常重要。他们能访问对方的数据,因为那些数据在同一个共享内存区,他们也共享资源像buffer空间和锁。与此同时,任何应用程序使用同一个数据库,必须共享一个环境,如
果想在他们之间保持一致性的话。
2:指定环境主路径:
所有DB文件都会从这个路径查找,按照如下顺序:
(1):如果没有指定任何路径,当前工作路径被使用
(2):如果环境主路径在DbEvn::open()中被指定,使用此路径
(3):如果在DbEvn::open()中指定了DB_USE_ENVIRON或者DB_USE_ENVIRON_USE,将会使用DB_HOME环境变量指定的路径
3:默认文件路径:
默认情况下,文件路径是依赖于环境主路径,可以指定绝对路径,使用"/"
4:几种文件的路径:
方法1:Evn::open()中指定环境路径
方法2:配置环境变量DB_HOME,Evn::open()会读取这个变量
方法3:
(1):database file采用DbEvn::set_data_dir()指定相对路径,它会附加到环境路径上
(2):log file采用DbEvn::set_lg_dir()
(3):region file总是保存在环境根目录下
(4):临时文件:DB_ENV->set_tmp_dir()
方法4:DB_CONFIG配置文件
优先级未知....
备注:DB_CONFIG 配置文件的目的是允许管理员定制不依赖于应用程序的环境。例如,可以移动数据库log文件和数据文件到不同的地方,而不用重新编译应用程序。另外,因为 DB_CONFIG文件是当数据库环境被打开时读取的,它可以用来覆盖在那以前配置的规则。例如,可以定义一个更合理的cache大小,来覆盖以前已经编 译到程序中的值
5:错误处理
1:Db::set_error_stream();
2:Db::set_errcall(); //错误发生时回调的函数
3:Db::set_errfile(); //错误发生时把错误写入一个文件
4:Db::set_errpfx(); //错误发生时错误消息的前缀
5:Db::err(); //发出一个错误消息,类似print的用法,会返回一个错误码
6:Db::errx); //基本同err(),但不返回错误码
6:Share Memory Regions
1:DB中的每个子系统(事务,锁,内存池,日志)在一个或者多个regions被描述,Regions包含所有这些需要在多进程或多线程中被共享的状态信息
2:Regions能够存储在文件系统,堆,系统共享内存中
(1):文件系统:默认设置,保存在环境根目录,命名规则为__db.xxx,比如__db.001
(2):堆:以这种方式创建的环境句柄不能被多进程共享,它也不会被写入文件系统中,使用方式为:
DbEvn::open()中指定DB_PRIVATE或者使用set_open_flags到DB_CONFIG文件中
(3):系统共享内存:DbEvn::open()中指定DB_SYSTEM_MEM
此时DB会在环境根目录下创建一个唯一的文件,它支持多进程共享环境句柄,Windows不能使用此选项
7:备注
应当关闭所有事务后再关闭数据库
Chapter 3:Transation Basics
1:基本操作
DbEvn::txn_begin()获得DbTxn指针
DbTxn::commit();
Dbtxn::abort();
当执行了commit或者abort,你的事务句柄就无效了,你必须使用新的句柄
2:事务实现方式
1:数据库的所有写操作都将被记录在日志系统中,默认情况下,这些日志被记录在磁盘上,当进程或者系统崩溃时,通过这些日志来维护数据库的一致性
2:DB使用write-ahead日志,也就是数据库的修改会先反应到日志中,然后再修改数据库文件,数据库同时在内存中维护日志,并同步到磁盘日志
3:自动提交
如果你只想对数据库德写操作加事务,可以使用autocommit,以后解释
4:事务过程
一个提交记录被写到内存日志文件,如果没有设置非持久化事务或者使用内存日志系统,日志会被同步到磁盘日志文件,然后关闭事务相关的锁
备注:事务的提交不表示修改的数据已经被写到文件中,能够导致真正的IO操作是:Checkpoint和cache full
5:非持久化事务
有几种方法:
1:DbEvn::set_flags()或者commit()时设置DB_TXN_NOSYNC,此时日志不会被同步到磁盘,当程序或者系统崩溃时会丢失数据
2: DbEvn::set_flags()设置DB_TXN_WRITE_NOSYNC,此时日志会被同步到系统的文件系统,并最终会被写到磁盘上,但这取决于操作系统的安排,这时事务的完成可能会快于磁盘IO,设置此标志能够对付程序的崩溃,但不能对付操作系统的崩溃
3:设置你的日志系统在内存中工作
- env.set_cachesize(0,300*1024*1024,0);
- env.log_set_config(DB_LOG_IN_MEMORY,1);
- env.set_lg_bsize(300*1024*1024);
6:Auto commit
指定DB_AUTO_COMMIT到DbEvn::open()或者Db::open()
备注:
1:游标不能使用Auto commit,应该显式的使用事务
2:单线程任何时候都只能有执行一个事务,否则会导致死锁
7:Nested Transations
1:当子事务启动时,父事务只能干三件事: 提交事务,放弃事务,开启新的子事务
2:子事务的提交不会影响到父事务,但这些修改只对父事务是可见的,对外部是不可见的直到父事务的提交
3:当父事务提交,放弃,子事务干同样的事
4:当子事务提交后它的锁不会被释放,直到父事务提交
5:子事务提交但父事务还没提交,则子事务的提交对外部不可见
6:子事务的层次限定只受限于内存
8:在游标中应用事务
1:创建一个事务,执行txn_begin();
2:创建游标的时候,将事务句柄传递进去
3:执行游标相关操作
4:提交或者放弃事务
9:在二级库中使用事务
当asscoiate时必须使用一个事务,简单的办法是传入DB_AUTO_COMMIT
10:事务设置
1:程序最大并发事务数量DbEnv::set_tx_max(),或者设置同名的DB_CONFIG,默认为20
2:设置事务超时值:DbEnv::set_timeout(),默认为0,绝对不会超时
Chapter 5:Managing DB Files
需要管理的文件包括:data file,log file,region file,temp file;我们只需管理data file和log file以支持备份,你也应该周期性的删除磁盘日志文件,并为你的程序选择合适的日志子系统实现方式
1:Checkpoint
1:只有当执行Checkpoint的时候数据才会被刷新到硬盘中,并且清除内存log中的数据页,我们可以周期性的执行cp,Checkpoint有以下特性
a:刷新将导致内存log中所有修改被写入到磁盘,即使这个事务还没有被提交,如果程序后来撤销了此事务,磁盘将还原这些修改的数据
b:写一个Checkpoint Record
c:刷新log,这将导致所有数据的写入
d:对于打开的数据库,选择一部分write
2:使用:
用一个线程调用DbEvn::txn_checkpoint(),这个函数还能设置有多少数据或者多少时间后才真正执行此函数
此函数的开销是很大的,因为它要遍历所有页面,但如果不够频繁,又会导致log变得非常巨大,所以要权衡这个问题
3:备份
备份三种方式:
1:offline backups:拷贝数据文件和日志文件到你想备份的地方,执行此备份时你不能执行写操作
2:hot backups:给数据库snapshot,snapshot的同时你的数据库可以执行写操作
3:incremental backups
4:offline backups步骤
1:提交或放弃所有的事务
2:暂停所有写操作
3:强制使用一次checkpoint
4:拷贝所有的数据库文件到你备份的地点
5:拷贝最后一个日志文件到你备份的地点,你的日志文件名字为log.xxxxx,数字最大的一个就是最后那个
5:Hot backup步骤
hot backup时,你不必停止数据库,备份的时候,事务可能在执行,也有可能正在进行写操作,也就是说:你不能确定备份的时候数据库的精确状态
第一种热备份方法:你可以使用db_hotbackup命令行创建一个热备份,这个命令将运行一个checkpoint和拷贝所有必须的文件到指定的目录
第二种热备份方法:
1:DbEvn::set_flag()设置DB_HOTBACKUP_IN_PROGRESS
2:拷贝所有的数据库文件到你备份的地点,使用DbEvn::log_archive()带DB_ARCH_DATA参数或者在数据库文件的目录下 使用db_archive命令行带-s选项列出所有数据库文件;如果想让备份成功,你必须拥有所有的日志文件,如果你删除了一些日志文件,那么这次备份不 能够被还原
3:拷贝所有日志文件到你的备份地点
4:重置DB_HOTBACKUP_IN_PROGRESS
6:Incremental backup步骤
增量备份不需要你运行checkpoint或者停止写操作
步骤:拷贝所有的日志文件到你的备份地点
备注:增量备份会带来大量的日志文件,你应该定期的执行一次全备份
7:Normal Recovery
普通还原一般在应用程序启动,第一次打开环境时运行
普通还原会仔细检查你的的日志,并使用这些日志文件来保证日志信息和数据库的一致性
普通还原会重建环境region file,并试图清理那些未被释放的锁和未正确关闭程序所带来的垃圾
普通还原会执行到日志文件的一个checkpoint为止
你应该在你应用程序开始时执行普通还原
步骤 方法1:
1:确保你所有的环境句柄被关闭
2:普通还原必须在单线程中执行
3:打开你的环境时指定DB_RECOVER标志
方法2:暂离或者关闭你的进程,并执行db_recover命令行
8:Catastrophic Recovery
使用以前的一个数据库备份恢复数据库则使用灾难恢复,在进行灾难恢复时,你应该拷贝一个备份到新的环境目录再运行灾难恢复
灾难恢复必须运行在单线程环境
步骤 方法1:
1:停止所有数据库操作
2:将备份放到一个空的目录
3:当你打开环境,提供DB_RECOVER_FATAL,打开这个环境必须是单线程
方法2:暂停或者关闭你的程序,执行db_recover命令行并添加-c选项
灾难恢复会检查所有的日志文件,所以灾难恢复会比普通恢复慢

9:为你的应用程序设计恢复策略
1:如果是单进程单线程环境:
在环境打开的时候采用简单恢复就可以了,你仅仅需要考虑到底是每次启动应用程序都恢复一次还是隔一段时间恢复一次
2:单进程多线程环境:
(1):如果你的应用程序只有一个环境句柄:在主线程打开环境并且指定恢复标志,然后在多线程中使用此环境句柄
(2):每个工作线程打开他自己的环境句柄,如果一个线程DB操作出现错误或者挂起,一般情况是重启程序,然后恢复,但不是所有程序都愿意当一个线程完蛋就重启整个进程,在这种情况下怎么怎么不看了
10:Hot Failover
对于一般的备份恢复,性能取决于:
1:备份设备一般在远端,你要先找到这个备份设备
2:将数据从备份设备拷贝到本地磁盘的速度
3:这个备份离现在有多长的事件
当使用Failover,一般情况下会使用本台主机的另外一块磁盘,这样的恢复会非常快,你只需要重新打开环境和数据库就可以了
Hot Failover不能确保绝对的安全...比如你主机爆炸了....
步骤:
1:拷贝所有活动数据库文件到failover目录,使用db_archive命令行和-s选项找出活动数据库文件
2:拷贝inactive log file到failover目录,使用db_archive不带选项找出这些文件
3:拷贝活动日志文件到failover目录,使用db_archive -l
4:在failover目录运行灾难恢复,使用db_recover -c
5:将这个备份存档
也可以采用db_hotbackup命令行
使用failover:
1:关闭所有在环境中运行的进程
2:...
删除日志文件
DB不会帮你删除日志文件,所以你应该周期性的删除日志文件,一个日志文件能够被删除必须同时满足以下原则
1:一个日志文件没有参与一个活动的事务
2:在日志文件创建后,一个checkpoint被执行
3:这个日志文件不是环境中唯一的日志文件
4:这个日志文件被包含在你的完全备份或者热备份中,如果违反这个原则,你的还原可能失败
DB不知道一个日志文件是否已经被包含在你的备份中,所以删除日志可能会导致一个不可用的备份,通过下面的方法可以帮你找到不需要的日志文件
1:db_archive -d
2:DbEnv::log_archive()带DB_ARCH_REMOVE
3:DbEnv::log_set_config()带DB_LOG_AUTO_REMOVE,这个标志可以在你程序任何时期设置,并且它会影响所有的环境,而不仅仅是调用者的环境
为了安全的移除这些日志文件并且还能进行灾难恢复,应该采用如下的方法使用db_archive命令
1:执行一次普通备份或者热备份
2:执行一次checkpoint
3:如果你有一个热备份,执行次热备份
4:在你的环境中执行db_archive -d
5:如果你有failover,在failover执行db_archive -d
日志子系统的配置
你可以配置
1:日志文件的大小
2:日志子系统region file大小
3:将整个日志子系统配置到内存中
4:日志内存缓存大小
5:日志文件在内存中的路径
浙公网安备 33010602011771号