2013年(350)
分类: Oracle
2013-04-25 13:09:51
有捕获,有传播,接下来应该就是应用了,真巧,也是这么想的。在复制环境中,共享对象的修改正是按照这样的逻辑被捕获->传播->应用。你可以在目标端配置一个或多个apply进程应用这些修改,下面我们再通过一些文字描述一下这个流程。
Apply 进程也是oracle的后台进程,专门出队并应用LCRs地干活。应用LCRs是由专门的apply user负责,apply user即可以通过自定义规则执行应用,也可以通过apply handler。
Apply 进程提供了非常灵活的机制处理LCRs,因此你可能需要针对不同配置情况做不同的选择,比如前面在讲传播时就曾提到的,单个apply进程要么应用捕获的LCR,要么应用user-enqueued LCR,而不能同时应用二者(如果某队列同时包含两种LCR的话,则应用端至少需要两个apply进程),你可以使用DBMS_STREAMS_ADM/DBMS_APPLY_ADM包创建apply进程应用捕获LCRs,如果要应用user-enqueued LCRs,则必须使用DBMS_APPLY_ADM.CREATE_APPLY过程创建应用进程。
下面分别介绍不同应用:
顾名思议即自动执行无须用户干预。Apply进程要么成功应用LCR中的修改到对象,要么应用时出错,出错的话将由conflict handler或用户自定义的error handler接管处理。
如果conflict handler能够解决冲突问题,其要么应用LCR,要么放弃相关修改。如果error handler能够处理错误,则应用该LCR,否则apply进程将该事务及LCRs相关的所有事务统统置入一个错误队列,等待用户手工处理,后面我们会有例子演示。
指Apply进程将lcr做为参数传送到用户自定义的过程中处理。用户自定义的处理row LCRs中DML语句的过程被称为DML handler,处理DDL LCRs中DDL语句的过程被称为DDL handler。一个apply进程可以有多个DML handlers,但是只能有一个DDL handler。
自定义应用非常灵活,你甚至可以为每个表的不同类型操作指定不同的DML handler处理。比如为hr.employees表的insert操作指定一个DML handler,为其update操作指定另一个DML handler。又比如你希望在某个目标库中跳过对hr.employees的delete操作,可以通过自定义DML handler的方式专门处理delete操作来实现这一目的。另外注意通常DML handler中不应有事务提交或回滚,除非是显式指定的savepoint。
另外对于DML/DDL handler,你可以指定一个precommit handler,该handler也是一个pl/sql实现的过程,其功能是从internal commit获取commit SCN。precommit handler能够以自定义的方式处理提交信息。
提示:
不要通过DML handlers/error handlers/自定义规则函数修改LONG,LONG RAW,nonassembled LOB列。下面分别描述apply进程应用过程中对关联项的处理
Apply 进程的parallelism参数控制应用的并行度。比如当该参数设置为1的时候,则只有一个apply进程按照事务在源端顺序一步步执行,这种情况下其实不需要考虑关联事务的问题,因为此时相当于是在串联执行,即不会有冲突也不会堵塞。需要注意的是当parallelism不为1时,多个apply进程可能同时应用多个事务,这些事务之间可能是有依赖和关联的,比如说源端a事务在b事务之前提交,但是目前端应用时为了提高应用效率,可能a/b两事务分别被不同apply进程同时调用,这个时候调用b事务的apply进程必然会等待调用a事务的apply进程执行完成了,再应用b事务中的修改。Apply进程会自动判断事务间的关联性。
分几种情况:
如果要更新的对象在目标端存在同名对象并且schema也相同,并且目标端对象定义了约束,apply进程会自动检测其在row LCRs中的依赖关系。
不管commit_serialization和parallelism参数值如何设置,apply进程总会优先考虑对象约束问题。比如apply进程应用一个事务时发现该事务包含的row LCRs依赖于另一个事务的row LCRs,则apply进程必须保证row LCRs以正确的顺序提交。
某些情况下,apply进程需要一些附加信息来检查并行应用情况下row LCRs中对象的关联情况,比如:
Virtual dependency definition,其实就是专用于apply进程的对象依赖信息的描述,用来在目标端检查事务间的关联性。Virtual dependency definitions不是以约束形式存在于目标端数据库,而是通过DBMS_APPLY_ADM包指定。Virtual dependency definitions提供了apply进程正确应用LCRs所需的必要信息,可以定义如下两种类型:
如果apply进程不能识别LCR中要更新的对象(即不存在于目标端数据库数据字典,也没有定义VDD),则该事务所包含的row LCR需要等到相同lower CSCN值的其它所有事务提交后再被应用,这种事务就被称为Barrier transaction。其它CSCN值高于该事务的也不会被应用,直到Barrier transaction提交。
必须确保主键列在源端操作时都被记录到redolog中,有多种方法能够确保操作被记录到redolog,比如附加日志。目标端的复合唯一键或外键约束在源库端必须需要启用附加日志。单列唯一键或外键则不需要,不过,如果源端约束列有多个,你也必须创建附加日志。
应尽可能给所有会被捕获的表创建主键或唯一键,前面捕获的部分三思已经介绍过相关内容,到应用的环节某些理论同样适用,比如说在应用/检测冲突等等时,oracle必须能够识别唯一列的信息,不然应用也无从做起。
默认情况下,Streams通过主键来唯一记录,如果没有定义主键,则通过最小的非空唯一键来确定记录唯一。如果上述两者都没有,你可以在目标端通过指定substitute key来唯一记录。
可以通过DBMS_APPLY_ADM.SET_KEY_COLUMNS过程设置substitute主键列,与真正的主键不同,substitute key列可以包含空值,并且substitute key列在应用时拥有更高的优先级,不过需要注意,如果你在目标端为表创建的substitute key引用列在源端表中并非是主键,那么务必在源端为该表启用附加日志。如果表即无主键也无唯一键,并且也未创建substitute key,那么apply进程会将该表除lob,long,long raw类型列除外的所有列组合在一起做为关键列,并且源端也必须为该表启用附加日志。
列差异是说源端和目标端相同表中列定义不同(可能是类型/长度不同,也可能是列名不存在),如果说streams复制环境中存在这种情况,一般可以通过rule-based转换或者DML handler处理器,下列各项描述的apply进程遇到列差异时的处理行为。
3.3.1. 列在目标端不存在如果要更新的列在目标端不存在,则apply进程抛出异常并移动该事务到error queue。这种问题可以通过创建rule-based转换或者配置DML handler,通过DELETE_COLUMN过程在应用前将列所在LCRs中不存在的列删除。
3.3.2. 列在源端不存在如果目标端的表拥有源端不存在的列,apply进程要视多出的列是否影响应用来决定其操作。如果额外列不影响应用的依赖关系,则apply进程直接应用修改。对于insert的操作如果额外列如果有默认值的话则插入默认值,否则该列值为null。
如果额外列影响应用,则apply进程也会将该事务置入error queue。
3.3.3. 列类型不同如果源端与目标端表中列的类型不同,apply进程应用时也会抛出错误并将事务置入error queue。要避免这种错误发生,也可以通过创建自定义的rule-based转换或DML handler处理。
Apply 进程只支持对不含下列ROWID,UROWID,User-defined types类型的索引组织表应用修改,如果含有上述类似,则应用时也会抛出异常。
多源的streams复制环境中有冲突是正常的,例如,在源端某表的记录被更新,同时目标端同名表的这些记录也被更新,当修改被传播到各自目标端的时候,apply进程在应用前就必须明确究竟是应用修改,还是保留本地的数据。Streams会自动检测冲突,对于update冲突如果配置了conflict handler会尝试使用解决。Streams提供了多种冲突解决方案,允许你根据自己的规则进行定制。
DML handler/Error handler/Update conflict handler 都可以处理row LCRs,不过注意同一个表的同一个操作不能同时定义DML handler和Error handler,下面分别描述配置了不同handler时的处理情况:
3.6.1. 没有配置handler如果没有配置任何handler,apply进程直接应用row LCR,如果成功则表被更新,如果失败则应用事务回滚并移动至错误队列。
3.6.2. Update conflict handler这种情况下apply进程也是尝试直接应用row LCR,如果成功则表被更新,如果由于非更新冲突(比如非唯一冲突或delete冲突)造成应用失败,则该事务回滚并移动至错误队列。如果由于更新造成失败,则update conflict handler被调用,如果update conflict handler能够解决冲突问题,则apply进程按照你配置了冲突解决方案应用或丢弃LCR,并继续应用该事务中其它LCRs。如果update conflict handler不能解决问题,则事务同样回滚并移动至错误队列。
3.6.3. DML handler这种情况下DML handler完全控制row LCR的处理。某些DML handler能够执行SQL操作或者运行EXECUTE member procedure。如果DML handler运行EXECUTE member procedure,则apply进程尝试应用row LCR。
提示:
什么是EXECUTE Member Procedure, 即在默认用户下执行 LCR。使用该方式应用LCR时,其它尝试应用该LCR的apply进程统统被该Apply进程接管处理,这就是前面说的完全控制row LCR的处理。如果DML handler执行的SQL操作失败,或者尝试运行EXECUTE member procedure失败,则DML handler尝试处理这种异常。如果DML handler没有报出异常,则apply进程就认为DML handler为row LCR执行了正确的操作,apply进程继续应用该事务中其它row LCR。
如果DML handler不能处理异常,则将错误抛出,该事务回滚并移动至错误队列。
3.6.4. DML handler + Update conflict handler这种情况下与单独配置DML handler相似,区别只在于如果DML handler执行的SQL操作失败,或者尝试运行EXECUTE member procedure遇到非update conflict导致的失败,则DML handler尝试处理这种异常。如果DML handler没有报出异常,则apply进程就认为DML handler为row LCR执行了正确的操作,apply进程继续应用该事务中其它row LCR。
如果由于update冲突导致EXECUTE member procedure执行失败,视EXECUTE member procedure参数conflict_resolution参数值的设置,apply进程执行不同的操作:
这种情况下由Error handler负责row LCR的处理,与DML handler类似,Error handler完全控制处理过程Error handler能够执行SQL操作或者运行EXECUTE member procedure。如果Error handler运行EXECUTE member procedure,则apply进程尝试应用row LCR。
如果Error handler执行的SQL操作失败,或者尝试运行EXECUTE member procedure失败,则Error handler尝试处理这种异常。如果Error handler没有报出异常,则apply进程就认为Error handler为row LCR执行了正确的操作,apply进程继续应用该事务中其它row LCR。
如果Error handler不能处理异常,则将错误抛出,该事务回滚并移动至错误队列。
3.6.6. Error handler + Update conflict handler这种情况下调用哪种handler去处理取决于错误类型:
======================================