Example of Potential Transactional Inconsistency

This example shows how to create two incremental autorefresh read-only cache groups.

The following example uses the employee and departments table, where the department id of the department table is a foreign key that points to the department id of the employee table.

The following example creates two incremental autorefresh read-only cache groups, where each is in its own cache group. The autorefresh transaction limit is enabled with ttCacheAutorefreshXactLimit before a large transaction and is disabled after it completes.

  1. Before you initiate the large transaction, invoke ttCacheAutorefreshXactLimit to set the interval value and the number of operations after which to automatically commit. The following sets the number of operations to three (which is intentionally low to show a brief example) for all incremental autorefresh read-only cache groups with a two second interval.

    CALL ttCacheAutorefreshXactLimit('2000', '3');
    < 2000, 3 >
    1 row found.
  2. Create the incremental autorefresh read-only cache groups with interval of two seconds. This example creates two static (non-dynamic) read-only cache groups, where each contains a single table.

    CREATE READONLY CACHE GROUP cgDepts AUTOREFRESH MODE INCREMENTAL 
     INTERVAL 2 SECONDS 
    FROM departments
        ( department_id    NUMBER(4) PRIMARY KEY
        , department_name  VARCHAR2(30) NOT NULL
        , manager_id       NUMBER(6)
        , location_id      NUMBER(4)
        );
     
    CREATE READONLY CACHE GROUP cgEmpls AUTOREFRESH MODE INCREMENTAL 
     INTERVAL 2 SECONDS 
    FROM employees
        ( employee_id    NUMBER(6) PRIMARY KEY
        , first_name     VARCHAR2(20)
        , last_name      VARCHAR2(25) NOT NULL
        , email          VARCHAR2(25) NOT NULL UNIQUE
        , phone_number   VARCHAR2(20)
        , hire_date      DATE NOT NULL
        , job_id         VARCHAR2(10) NOT NULL
        , salary         NUMBER(8,2)
        , commission_pct NUMBER(2,2)
        , manager_id     NUMBER(6)
        , department_id  NUMBER(4)
        );
  3. Run a LOAD CACHE GROUP statement for both cache groups with autorefresh.

    LOAD CACHE GROUP cgDepts COMMIT EVERY 256 ROWS;
    27 cache instances affected.
     
    LOAD CACHE GROUP cgEmpls COMMIT EVERY 256 ROWS;
    107 cache instances affected.

You can have inconsistency within the table during an autorefresh as shown with the employees table.

  1. On TimesTen, select the minimum and maximum salary of all employees.

    SELECT MIN(salary), MAX(salary) FROM employees;
    < 2100, 24000 >
    1 row found.
  2. On the Oracle database, add 100,000 to everyone's salary.

    UPDATE employees SET salary = salary + 100000;
    107 rows updated.
  3. On TimesTen, when you run the SELECT again (while the autorefresh transactions are commmitted after every 3 records), it shows that while the maximum salary has updated, the minimum salary is still the old value.

    SELECT MIN(salary), MAX(salary) FROM employees;
    < 2100, 124000 >
    1 row found.
  4. However, once the autorefresh completes, transactional consistency is maintained. For this example, once the autorefresh process completes, all salaries have increased by 100,000.

    SELECT MIN(salary), MAX(salary) FROM employees;
    < 102100, 124000 >
    1 row found.
  5. The large transaction is complete, so disable the transaction limit for cache groups with a 2 second interval autorefresh.

    call ttCacheAutorefreshXactLimit('2000', 'OFF');

You can have transactional inconsistency between cache groups if you run a SQL statement while the autorefresh process is progressing. The following SELECT statement example runs against the employees and department table in the cgDepts autorefresh cache group. With this example, since the foreign key is not enforced on TimesTen and the autorefresh process applies several transactions, the employee table updates may be inserted before the department updates.

In addition, all of the updates for both tables in the cache group are not applied until the autorefresh cycle has completed. In the following example, the SELECT statement is performed before the autorefresh process is complete. Thus, the results do not show all of the expected data, such as the department name and several employees (some of the lawyers in the legal department 1000) are missing.

SELECT e.department_id, d.DEPARTMENT_NAME, e.FIRST_NAME, e.LAST_NAME  
       FROM employees e, departments d         
       WHERE e.DEPARTMENT_ID  = d.DEPARTMENT_ID (+) 
       AND e.department_id >= 1000 ORDER BY 1,2,3,4;
< 1000, Legal, Alec, Dunkle >
< 1000, Legal, Barry, Strong >
< 1000, Legal, Leigh, Harrison >
3 rows found.

However, after the autorefresh process completes, transactional consistency is maintained. The following shows the same SELECT statement performed after the autorefresh is complete. All expected data, the department information and all of the new lawyers, are updated.

SELECT e.department_id, d.DEPARTMENT_NAME, e.FIRST_NAME, e.LAST_NAME  
       FROM employees e, departments d         
       WHERE e.DEPARTMENT_ID  = d.DEPARTMENT_ID (+) 
       AND e.department_id >= 1000 ORDER BY 1,2,3,4;
< 1000, Legal, Alec, Dunkle >
< 1000, Legal, Barry, Strong >
< 1000, Legal, Leigh, Harrison >
< 1000, Legal, John, Crust >
< 1000, Legal, Robert, Wright >
< 1000, Legal, Robert, Smith >
6 rows found.

For cache groups with autorefresh that have more than one table, you can also experience transactional inconsistency if you run SQL statements while the autorefresh process is in progress.

  1. Initiate the transaction limit for incremental cache groups with autorefresh of 2 seconds with the ttCacheAutorefreshXactLimit built-in procedure and create a single autorefresh cache group with two tables: the employees and departments tables.
    CALL ttCacheAutorefreshXactLimit('2000', '3');
    < 2000, 3 >
    1 row found.
     
    CREATE READONLY CACHE GROUP cgDeptEmpls AUTOREFRESH MODE INCREMENTAL
     INTERVAL 2 SECONDS 
    FROM departments
         ( department_id    NUMBER(4) PRIMARY KEY
         , department_name  VARCHAR2(30) NOT NULL
         , manager_id       NUMBER(6)
         , location_id      NUMBER(4)
         )
       , employees
         ( employee_id    NUMBER(6) PRIMARY KEY
         , first_name     VARCHAR2(20)
         , last_name      VARCHAR2(25) NOT NULL
         , email          VARCHAR2(25) NOT NULL UNIQUE
         , phone_number   VARCHAR2(20)
         , hire_date      DATE NOT NULL
         , job_id         VARCHAR2(10) NOT NULL
         , salary         NUMBER(8,2)
         , commission_pct NUMBER(2,2)
         , manager_id     NUMBER(6)
         , department_id  NUMBER(4)
         , foreign key(department_id) references departments(department_id)
         );
  2. Manually load the cache group.
    LOAD CACHE GROUP cgDeptEmpls COMMIT EVERY 256 ROWS;
    27 cache instances affected.
  3. Run a SELECT statement on TimesTen that uploads all of the legal department data.
    SELECT e.department_id, d.department_name, count(*)
           FROM employees e, departments d         
           WHERE e.department_id  = d.department_id (+) 
           GROUP BY e.department_id, d.department_name
           ORDER BY 1 desc;
    < 110, Accounting, 2 >
    < 100, Finance, 6 >
    < 90, Executive, 3 >
    < 80, Sales, 34 >
    < 70, Public Relations, 1 >
    < 60, IT, 5 >
    < 50, Shipping, 45 >
    < 40, Human Resources, 1 >
    < 30, Purchasing, 6 >
    < 20, Marketing, 2 >
    < 10, Administration, 1 >
    11 rows found.
  4. On Oracle, insert a new legal department, numbered 1000, with 6 new lawyers in both the employee and department tables.
  5. When performing a SELECT statement on TimesTen during the autorefresh process, only data on two of the lawyers in department 1000 have been uploaded into TimesTen.
    SELECT e.department_id, d.department_name, count(*)
           FROM employees e, departments d         
           WHERE e.department_id  = d.department_id (+) 
           GROUP BY e.department_id, d.department_name
           ORDER BY 1 desc;
    < 1000, Legal, 2 >
    < 110, Accounting, 2 >
    < 100, Finance, 6 >
    < 90, Executive, 3 >
    < 80, Sales, 34 >
    < 70, Public Relations, 1 >
    < 60, IT, 5 >
    < 50, Shipping, 45 >
    < 40, Human Resources, 1 >
    < 30, Purchasing, 6 >
    < 20, Marketing, 2 >
    < 10, Administration, 1 >
    12 rows found.
  6. However, after the autorefresh process completes, all 6 employees (lawyers) in the legal department have been uploaded to TimesTen. Now, it is transactionally consistent.
    SELECT e.department_id, d.department_name, COUNT(*)
           FROM employees e, departments d         
           WHERE e.department_id  = d.department_id (+) 
           GROUP BY e.department_id, d.department_name
           ORDER BY 1 desc;
    < 1000, Legal, 6 >
    < 110, Accounting, 2 >
    < 100, Finance, 6 >
    < 90, Executive, 3 >
    < 80, Sales, 34 >
    < 70, Public Relations, 1 >
    < 60, IT, 5 >
    < 50, Shipping, 45 >
    < 40, Human Resources, 1 >
    < 30, Purchasing, 6 >
    < 20, Marketing, 2 >
    < 10, Administration, 1 >
    12 rows found.
  7. The large transaction is complete, so disable the transaction limit for cache groups with a 2 second autorefresh interval.
    call ttCacheAutorefreshXactLimit('2000', 'OFF');