Oracle® Streams Replication Administrator's Guide 10g Release 1 (10.1) Part Number B10728-01 |
|
|
View PDF |
Some Streams environments must use conflict handlers to resolve possible data conflicts that can result from sharing data between multiple databases.
This chapter contains these topics:
Conflicts can occur in a Streams environment that permits concurrent data manipulation language (DML) operations on the same data at multiple databases. In a Streams environment, DML conflicts can occur only when an apply process is applying an event that contains a row change resulting from a DML operation. This type of event is called a row logical change record, or row LCR. An apply process automatically detects conflicts caused by row LCRs.
For example, when two transactions originating at different databases update the same row at nearly the same time, a conflict can occur. When you configure a Streams environment, you must consider whether conflicts can occur. You can configure conflict resolution to resolve conflicts automatically, if your system design permits conflicts.
In general, you should try to design a Streams environment that avoids the possibility of conflicts. Using the conflict avoidance techniques discussed later in this chapter, most system designs can avoid conflicts in all or a large percentage of the shared data. However, many applications require that some percentage of the shared data be updatable at multiple databases at any time. If this is the case, then you must address the possibility of conflicts.
Note: An apply process does not detect DDL conflicts or conflicts resulting from user-enqueued events. Make sure your environment avoids these types of conflicts. |
See Also:
Oracle Streams Concepts and Administration for more information about row LCRs |
You may encounter these types of conflicts when you share data at multiple databases:
An update conflict occurs when the apply process applies a row LCR containing an update to a row that conflicts with another update to the same row. Update conflicts can happen when two transactions originating from different databases update the same row at nearly the same time.
A uniqueness conflict occurs when the apply process applies a row LCR containing a change to a row that violates a uniqueness integrity constraint, such as a PRIMARY
KEY
or UNIQUE
constraint. For example, consider what happens when two transactions originate from two different databases, each inserting a row into a table with the same primary key value. In this case, the transactions cause a uniqueness conflict.
A delete conflict occurs when two transactions originate at different databases, with one transaction deleting a row and another transaction updating or deleting the same row. In this case, the row referenced in the row LCR does not exist to be either updated or deleted.
A foreign key conflict occurs when the apply process applies a row LCR containing a change to a row that violates a foreign key constraint. For example, in the hr
schema, the department_id
column in the employees
table is a foreign key of the department_id
column in the departments
table. Consider what can happen when the following changes originate at two different databases (A
and B
) and are propagated to a third database (C
):
A
, a row is inserted into the departments
table with a department_id
of 271
. This change is propagated to database B
and applied there.B
, a row is inserted into the employees
table with an employee_id
of 206
and a department_id
of 271
.If the change that originated at database B
is applied at database C
before the change that originated at database A
, then a foreign key conflict results because the row for the department with a department_id
of 271
does not yet exist in the departments
table at database C
.
Ordering conflicts can occur in a Streams environment when three or more databases share data and the data is updated at two or more of these databases. For example, consider a scenario in which three databases share information in the hr.departments
table. The database names are mult1.net
, mult2.net
, and mult3.net
. Suppose a change is made to a row in the hr.departments
table at mult1.net
that will be propagated to both mult2.net
and mult3.net
. The following series of actions may occur:
mult2.net
.mult2.net
applies the change from mult1.net
.mult2.net
.mult2.ne
t is propagated to mult3.net
.mult3.net
attempts to apply the change from mult2.net
before another apply process at mult3.net
applies the change from mult1.net
.In this case, a conflict occurs because a column value for the row at mult3.net
does not match the corresponding old value in the row LCR propagated from mult2.net
.
In addition to causing a data conflict, transactions that are applied out of order might experience referential integrity problems at a remote database if supporting data has not been successfully propagated to that database. Consider the scenario where a new customer calls an order department. A customer record is created and an order is placed. If the order data is applied at a remote database before the customer data, then a referential integrity error is raised because the customer that the order references does not exist at the remote database.
If an ordering conflict is encountered, then you can resolve the conflict by reexecuting the transaction in the error queue after the required data has been propagated to the remote database and applied.
An apply process detects update, uniqueness, delete, and foreign key conflicts as follows:
A conflict may be detected when an apply process attempts to apply an LCR directly or when an apply process handler, such as a DML handler, runs the EXECUTE
member procedure for an LCR. A conflict also may be detected when either the EXECUTE_ERROR
or EXECUTE_ALL_ERRORS
procedure in the DBMS_APPLY_ADM
package is run.
Note: Any old LOB values in update LCRs, delete LCRs, and LCRs dealing with piecewise updates to LOB columns are not used by conflict detection. |
By default, an apply process compares old values for all columns during conflict detection, but you can stop conflict detection for nonkey columns using the COMPARE_OLD_VALUES
procedure in the DBMS_APPLY_ADM
package. Conflict detection may not be needed for some nonkey columns.
To detect conflicts accurately, Oracle must be able to identify and match corresponding rows at different databases uniquely. By default, Oracle uses the primary key of a table to identify rows in a table uniquely. When a table does not have a primary key, you should designate a substitute key. A substitute key is a column or set of columns that Oracle can use to identify uniquely rows in the table.
This section describes ways to avoid data conflicts.
You can avoid the possibility of conflicts by limiting the number of databases in the system that have simultaneous update access to the tables containing shared data. Primary ownership prevents all conflicts, because only a single database permits updates to a set of shared data. Applications can even use row and column subsetting to establish more granular ownership of data than at the table level. For example, applications might have update access to specific columns or rows in a shared table on a database-by-database basis.
If a primary database ownership model is too restrictive for your application requirements, then you can use a shared ownership data model, which means that conflicts may be possible. Even so, typically you can use some simple strategies to avoid specific types of conflicts.
You can avoid uniqueness conflicts by ensuring that each database uses unique identifiers for shared data. There are three ways to ensure unique identifiers at all databases in a Streams environment.
One way is to construct a unique identifier by executing the following select statement:
SELECT SYS_GUID() OID FROM DUAL;
This SQL operator returns a 16-byte globally unique identifier. This value is based on an algorithm that uses time, date, and the computer identifier to generate a globally unique identifier. The globally unique identifier appears in a format similar to the following:
A741C791252B3EA0E034080020AE3E0A
Another way to avoid uniqueness conflicts is to create a sequence at each of the databases that shares data and concatenate the database name (or other globally unique value) with the local sequence. This approach helps to avoid any duplicate sequence values and helps to prevent uniqueness conflicts.
Finally, you can create a customized sequence at each of the databases that shares data so that no two databases can generate the same value. You can accomplish this by using a combination of starting, incrementing, and maximum values in the CREATE
SEQUENCE
statement. For example, you might configure the following sequences:
Parameter | Database A | Database B | Database C |
---|---|---|---|
|
1 |
3 |
5 |
|
10 |
10 |
10 |
Range Example |
1, 11, 21, 31, 41,... |
3, 13, 23, 33, 43,... |
5, 15, 25, 35, 45,... |
Using a similar approach, you can define different ranges for each database by specifying a START
WITH
and MAXVALUE
that would produce a unique range for each database.
Always avoid delete conflicts in shared data environments. In general, applications that operate within a shared ownership data model should not delete rows using DELETE
statements. Instead, applications should mark rows for deletion and then configure the system to purge logically deleted rows periodically.
After trying to eliminate the possibility of uniqueness and delete conflicts, you should also try to limit the number of possible update conflicts. However, in a shared ownership data model, update conflicts cannot be avoided in all cases. If you cannot avoid all update conflicts, then you must understand the types of conflicts possible and configure the system to resolve them if they occur.
After an update conflict has been detected, a conflict handler can attempt to resolve it. Streams provides prebuilt conflict handlers to resolve update conflicts, but not uniqueness, delete, foreign key, or ordering conflicts. However, you can build your own custom conflict handler to resolve data conflicts specific to your business rules. Such a conflict handler can be part of a DML handler or an error handler.
Whether you use prebuilt or custom conflict handlers, a conflict handler is applied as soon as a conflict is detected. If neither the specified conflict handler nor the relevant apply handler can resolve the conflict, then the conflict is logged in the error queue. You may want to use the relevant apply handler to notify the database administrator when a conflict occurs.
When a conflict causes a transaction to be moved to the error queue, sometimes it is possible to correct the condition that caused the conflict. In these cases, you can reexecute a transaction using the EXECUTE_ERROR
procedure in the DBMS_APPLY_ADM
package.
See Also:
|
This section describes the types of prebuilt update conflict handlers available to you and how column lists and resolution columns are used in prebuilt update conflict handlers. A column list is a list of columns for which the update conflict handler is called when there is an update conflict. The resolution column is the column used to identify an update conflict handler. If you use a MAXIMUM
or MINIMUM
prebuilt update conflict handler, then the resolution column is also the column used to resolve the conflict. The resolution column must be one of the columns in the column list for the handler.
Use the SET_UPDATE_CONFLICT_HANDLER
procedure in the DBMS_APPLY_ADM
package to specify one or more update conflict handlers for a particular table. There are no prebuilt conflict handlers for uniqueness, delete, or foreign key conflicts.
See Also:
|
Oracle provides the following types of prebuilt update conflict handlers for a Streams environment: OVERWRITE
, DISCARD
, MAXIMUM
, and MINIMUM
.
The description for each type of handler later in this section refers to the following conflict scenario:
dbs1.net
source database:
UPDATE hr.employees SET salary = 4900 WHERE employee_id = 200; COMMIT;
This update changes the salary for employee 200
from 4400
to 4900
.
dbs2.net
destination database:
UPDATE hr.employees SET salary = 5000 WHERE employee_id = 200; COMMIT;
dbs1.net
source database and puts the resulting row LCR in a queue.dbs1.net
to a queue at dbs2.net
.dbs2.net
attempts to apply the row LCR to the hr.employees
table but encounters a conflict because the salary value at dbs2.net
is 5000
, which does not match the old value for the salary in the row LCR (4400
).The following sections describe each prebuilt conflict handler and explain how the handler resolves this conflict.
When a conflict occurs, the OVERWRITE
handler replaces the current value at the destination database with the new value in the LCR from the source database.
If the OVERWRITE
handler is used for the hr.employees
table at the dbs2.net
destination database in the conflict example, then the new value in the row LCR overwrites the value at dbs2.net
. Therefore, after the conflict is resolved, the salary for employee 200
is 4900
.
When a conflict occurs, the DISCARD
handler ignores the values in the LCR from the source database and retains the value at the destination database.
If the DISCARD
handler is used for the hr.employees
table at the dbs2.net
destination database in the conflict example, then the new value in the row LCR is discarded. Therefore, after the conflict is resolved, the salary for employee 200
is 5000
at dbs2.net
.
When a conflict occurs, the MAXIMUM
conflict handler compares the new value in the LCR from the source database with the current value in the destination database for a designated resolution column. If the new value of the resolution column in the LCR is greater than the current value of the column at the destination database, then the apply process resolves the conflict in favor of the LCR. If the new value of the resolution column in the LCR is less than the current value of the column at the destination database, then the apply process resolves the conflict in favor of the destination database.
If the MAXIMUM
handler is used for the salary
column in the hr.employees
table at the dbs2.net
destination database in the conflict example, then the apply process does not apply the row LCR, because the salary in the row LCR is less than the current salary in the table. Therefore, after the conflict is resolved, the salary for employee 200
is 5000
at dbs2.net
.
If you want to resolve conflicts based on the time of the transactions involved, then one way to do this is to add a column to a shared table that automatically records the transaction time with a trigger. You can designate this column as a resolution column for a MAXIMUM
conflict handler, and the transaction with the latest (or greater) time would be used automatically.
The following is an example of a trigger that records the time of a transaction for the hr.employees
table. Assume that the job_id
, salary
, and commission_pct
columns are part of the column list for the conflict resolution handler. The trigger should fire only when an UPDATE
is performed on the columns in the column list or when an INSERT
is performed.
CONNECT hr/hr ALTER TABLE hr.employees ADD (time TIMESTAMP WITH TIME ZONE); CREATE OR REPLACE TRIGGER hr.insert_time_employees BEFORE INSERT OR UPDATE OF job_id, salary, commission_pct ON hr.employees FOR EACH ROW BEGIN -- Consider time synchronization problems. The previous update to this -- row may have originated from a site with a clock time ahead of the -- local clock time. IF :OLD.TIME IS NULL OR :OLD.TIME < SYSTIMESTAMP THEN :NEW.TIME := SYSTIMESTAMP; ELSE :NEW.TIME := :OLD.TIME + 1 / 86400; END IF; END; /
If you use such a trigger for conflict resolution, then make sure the trigger's firing property is fire once, which is the default. Otherwise, a new time may be marked when transactions are applied by an apply process, resulting in the loss of the actual time of the transaction.
When a conflict occurs, the MINIMUM
conflict handler compares the new value in the LCR from the source database with the current value in the destination database for a designated resolution column. If the new value of the resolution column in the LCR is less than the current value of the column at the destination database, then the apply process resolves the conflict in favor of the LCR. If the new value of the resolution column in the LCR is greater than the current value of the column at the destination database, then the apply process resolves the conflict in favor of the destination database.
If the MINIMUM
handler is used for the salary
column in the hr.employees
table at the dbs2.net
destination database in the conflict example, then the apply process resolves the conflict in favor of the row LCR, because the salary in the row LCR is less than the current salary in the table. Therefore, after the conflict is resolved, the salary for employee 200
is 4900
.
Each time you specify a prebuilt update conflict handler for a table, you must specify a column list. A column list is a list of columns for which the update conflict handler is called. If an update conflict occurs for one or more of the columns in the list when an apply process tries to apply a row LCR, then the update conflict handler is called to resolve the conflict. The update conflict handler is not called if a conflict occurs only in columns that are not in the list. The scope of conflict resolution is a single column list on a single row LCR.
You can specify more than one update conflict handler for a particular table, but the same column cannot be in more than one column list. For example, suppose you specify two prebuilt update conflict handlers on hr.employees
table:
salary
and commission_pct
.job_id
and department_id
.Also, assume that no other conflict handlers exist for this table. In this case, if a conflict occurs for the salary
column when an apply process tries to apply a row LCR, then the first update conflict handler is called to resolve the conflict. If, however, a conflict occurs for the department_id
column, then the second update conflict handler is called to resolve the conflict. If a conflict occurs for a column that is not in a column list for any conflict handler, then no conflict handler is called, and an error results. In this example, if a conflict occurs for the manager_id
column in the hr.employees
table, then an error results. If conflicts occur in more than one column list when a row LCR is being applied, and there are no conflicts in any columns that are not in a column list, then the appropriate update conflict handler is invoked for each column list with a conflict.
Column lists enable you to use different handlers to resolve conflicts for different types of data. For example, numeric data is often suited for a maximum or minimum conflict handler, while an overwrite or discard conflict handler might be preferred for character data.
If a conflict occurs in a column that is not in a column list, then the error handler for the specific operation on the table attempts to resolve the conflict. If the error handler cannot resolve the conflict, or if there is no such error handler, then the transaction that caused the conflict is moved to the error queue.
Also, if a conflict occurs for a column in a column list that uses either the OVERWRITE
, MAXIMUM
, or MINIMUM
prebuilt handler, and the row LCR does not contain all of the columns in this column list, then the conflict cannot be resolved because all of the values are not available. In this case, the transaction that caused the conflict is moved to the error queue. If the column list uses the DISCARD
prebuilt method, then the row LCR is discarded and no error results, even if the row LCR does not contain all of the columns in this column list.
A conditional supplemental log group must be specified for the columns specified in a column list if more than one column at the source database affects the column list at the destination database. Supplemental logging is specified at the source database and adds additional information to the LCR, which is needed to resolve conflicts properly. Typically, a conditional supplemental log group must be specified for the columns in a column list if there is more than one column in the column list, but not if there is only one column in the column list.
However, in some cases, a conditional supplemental log group is required even if there is only one column in a column list. That is, an apply handler or rule-based transformation may combine multiple columns from the source database into a single column in the column list at the destination database. For example, a rule-based transformation may take three columns that store street, state, and postal code data from a source database and combine the data into a single address column at a destination database.
Also, in some cases, no conditional supplemental log group is required even if there is more than one column in a column list. For example, an apply handler or rule-based transformation may separate one address column from the source database into multiple columns that are in a column list at the destination database. A rule-based transformation may take an address that includes street, state, and postal code data in one address column at a source database and separate the data into three columns at a destination database.
The resolution column is the column used to identify an update conflict handler. If you use a MAXIMUM
or MINIMUM
prebuilt update conflict handler, then the resolution column is also the column used to resolve the conflict. The resolution column must be one of the columns in the column list for the handler.
For example, if the salary
column in the hr.employees
table is specified as the resolution column for a maximum or minimum conflict handler, then the salary
column is evaluated to determine whether column list values in the row LCR are applied or the destination database values for the column list are retained.
In either of the following situations involving a resolution column for a conflict, the apply process moves the transaction containing the row LCR that caused the conflict to the error queue, if the error handler cannot resolve the problem. In these cases, the conflict cannot be resolved and the values of the columns at the destination database remain unchanged:
NULL
.
When you share data between multiple databases, and you want the data to be the same at all of these databases, then make sure you use conflict resolution handlers that cause the data to converge at all databases. If you allow changes to shared data at all of your databases, then data convergence for a table is possible only if all databases that are sharing data capture changes to the shared data and propagate these changes to all of the other databases that are sharing the data.
In such an environment, the MAXIMUM
conflict resolution method can guarantee convergence only if the values in the resolution column are always increasing. A time-based resolution column meets this requirement, as long as successive timestamps on a row are distinct. The MINIMUM
conflict resolution method can guarantee convergence in such an environment only if the values in the resolution column are always decreasing.
You can create a PL/SQL procedure to use as a custom conflict handler. You use the SET_DML_HANDLER
procedure in the DBMS_APPLY_ADM
package to designate one or more custom conflict handlers for a particular table. Specifically, set the following parameters when you run this procedure to specify a custom conflict handler:
object_name
parameter to the fully qualified name of the table for which you want to perform conflict resolution.object_type
parameter to TABLE
.operation_name
parameter to the type of operation for which the custom conflict handler is called. The possible operations are the following: INSERT
, UPDATE
, DELETE
, and LOB_UPDATE
.error_handler
parameter to true
. Or, if you want to include conflict resolution in your DML handler, then set the error_handler
parameter to false
.
If you specify false
for this parameter, then, when you execute a row LCR using the EXECUTE
member procedure for the LCR, the conflict resolution within the DML handler is performed for the specified object and operation(s).
user_procedure
parameter. This user procedure is called to resolve any conflicts on the specified table resulting from the specified type of operation.If the custom conflict handler cannot resolve the conflict, then the apply process moves the transaction containing the conflict to the error queue and does not apply the transaction.
If both a prebuilt update conflict handler and a custom conflict handler exist for a particular object, then the prebuilt update conflict handler is invoked only if both of the following conditions are met:
EXECUTE
member procedure for the LCR.conflict_resolution
parameter in the EXECUTE
member procedure for the row LCR is set to true
.
See Also:
|