Scalable Database Server, HiRDB Version 8 UAP Development Guide
Actual work operations involve numbering, including management of form and document numbers. There are instances when two users may try to get form numbers at the same time. The form numbers must be counted to ensure that when a user requests a form number, he or she does not get the same number that was issued earlier to another user. If a duplicate number is generated, a user may be forced to wait while another user is getting a form number. HiRDB provides a numbering function to minimize the effects of lock-release waiting.
For the most efficient numbering, tables must be designed to minimize the effects of lock-release waiting. HiRDB minimizes the locking effects on tables that manage numbers by providing a facility that releases the lock on a row without waiting for the UAP to commit the transaction. This facility releases the lock when the table update (including addition and deletion) process is completed and disables rollback after that point. To use this facility, the table designer must specify the WITHOUT ROLLBACK option in the CREATE TABLE statement when defining the table.
If the WITHOUT ROLLBACK option is specified when a table is defined, rollback becomes disabled as soon as a row is updated. Thus, if the UAP or the HiRDB system terminates abnormally, the active table with obtained numbers is rolled back correctly when the HiRDB system is restarted, and data integrity is maintained. However, the point to which the process that updates the number management table was rolled back is unknown. In this case, the operation has assigned a number but is no longer using it. Therefore, the WITHOUT ROLLBACK option is not suitable for operations that are adversely affected if a number is skipped. Use the WITHOUT ROLLBACK option only if the numbers do not have to be continuous.
Figure 4-63 shows an example of a table that manages numbers.
Figure 4-63 Example of a table that manages numbers
Following is an example of a numbering application program. The application program that manipulates the number management table and the operation table is assumed to be the same transaction.
This table manages form numbers and document numbers. In the following example, the SQL obtains the latest form number from the number management table and uses it in the operation.
INSERT INTO number-management-table VALUE ('form-number',1) 1 : DECLARE CUR1 CURSOR FOR 2 SELECT number FROM number-management-table WHERE type='form-number' FOR UPDATE OF number OPEN CUR1 3 FETCH CUR1 INTO :x_number 4 UPDATE number-management-table SET number=:x_number+1 5 WHERE CURRENT OF CUR1 CLOSE CUR1 6 : Access to operation table that used obtained number 7 :
Steps 3 through 7 are repeated for each number.
If multiple rows are stored in a table for which the WITHOUT ROLLBACK option is specified and an index is not defined for that table, all rows are temporarily locked because the retrieval targets all rows. In such cases, a lock-release wait may occur between the form number numbering process and the document number numbering process. To avoid lock-release wait, specify YES for PDLOCKSKIP in the client environment definitions. This sets a search using condition evaluation with no lock. When a search using condition evaluation with no lock is set, the rows are not locked during retrieval processing, and only the rows that satisfy the retrieval condition are locked.
When handling multiple number types, do not execute processes that update multiple rows with one SQL execution. Lock release and rollback become disabled in each row when update processing for that row is completed. Therefore, if a UAP that updates multiple rows terminates abnormally, the HiRDB system may not be able to roll back the update of some of the rows.
Registering a numbering process as a stored procedure is useful because numbering is often processed according to a fixed pattern.
Examples 1 through 3 show table definitions and stored procedures.
CREATE FIX TABLE owner_id.sequence_tbl(sequence_no INTEGER NOT NULL) WITHOUT ROLLBACK; 1 CREATE PROCEDURE owner_id.nextval(OUT next_no INTEGER) BEGIN DECLARE update_no INTEGER; 2 DECLARE cr1 CURSOR FOR SELECT sequence_no FROM owner_id.sequence_tbl FOR UPDATE; OPEN cr1; FETCH cr1 INTO update_no; 3 SET next_no=update_no; 4 UPDATE owner_id.sequence_tbl SET sequence_no=update_ no+1 WHERE CURRENT OF cr1; 5 CLOSE cr1; 3 END 2 COMMIT WORK; 6 INSERT INTO owner_id.sequence_tbl(sequence_no) VALUES(1); 7 COMMIT WORK; 8 <Sequence number assignment> 9 CALL owner_id.nextval (OUT:xnext_no); : Process that uses sequence number xnext_no that was assigned : CALL owner_id.nextval (OUT:xnext_no); :
CREATE FIX TABLE owner_id.sequence_tbl(sequence_key CHAR(30) NOT NULL, sequence_no INTEGER NOT NULL) WITHOUT ROLLBACK; ..........................................1 CREATE PROCEDURE owner_id.nextval(IN input_key CHAR(30), OUT next_no INTEGER) BEGIN DECLARE update_no INTEGER; .................................2 DECLARE cr1 CURSOR FOR SELECT sequence_no FROM owner_id.sequence_tbl WHERE sequence_key=input_key FOR UPDATE OF sequence_no; OPEN cr1; FETCH cr1 INTO update_no; ..................................3 SET next_no=update_no; .....................................4 UPDATE owner_id.sequence_tbl SET sequence_no=update_no+1 WHERE CURRENT OF cr1; ....................................5 CLOSE cr1; .................................................3 END ..........................................................2 COMMIT WORK; ...................................................6 INSERT INTO owner_id.sequence_tbl(sequence_key,sequence_no) VALUES('key_value_1',1); ...................................7 COMMIT WORK; ...................................................8 INSERT INTO owner_id.sequence_tbl(sequence_key,sequence_no) VALUES('key_value_2',1); ...................................7 COMMIT WORK; ...................................................8 : (Initial value row is inserted for each sequence number type) <Assignment of 'key_value_1' sequence number> ............................9 xinput_key <-- 'key_value_1' CALL owner_id.nextval(IN:xinput_key,OUT:xnext_no); : Processing when sequence number xnext_no assigned to 'seqkey_value_1' is used : xinput_key <-- 'key_value_1' CALL owner_id.nextval(IN:xinput_key,OUT:xnext_no); : <'Assignment of key_value_2' sequence number> ............................9 xinput_key <-- 'key_value_2' CALL owner_id.nextval(IN :xinput_key,OUT:xnext_no); : Processing when sequence number xnext_no assigned to 'key_value_2' is used : xinput_key <-- 'key_value_2' CALL owner_id.nextval(IN:xinput_key,OUT:xnext_no); :
CREATE FIX TABLE owner_id.sequence_tbl (sequence_no INTEGER NOT NULL) WITHOUT ROLLBACK; 1 CREATE PROCEDURE owner_id.nextval(OUT next_no INTEGER) BEGIN DECLARE update_no INTEGER; 2 DECLARE cr1 CURSOR FOR SELECT sequence_no FROM owner_id.sequence_tbl FOR UPDATE; OPEN cr1; FETCH cr1 INTO update_no; 3 SET next_no=update_no; 4 IF update_no=214783647 THEN SET update_no=-214783648; ELSE SET update_no=update_no+1; END IF; 5 UPDATE owner_id.sequence_tbl SET sequence_no=update_no WHERE CURRENT OF cr1 6 CLOSE cr1; 3 END 2 COMMIT WORK; 7 INSERT INTO owner_id.sequence_tbl(sequence_no)VALUES(1); 8 COMMIT WORK; 9 <Sequence number assignment> 10 CALL owner_id.nextval(OUT:xnext_no); : Process that uses sequence number xnext_no that was assigned : CALL owner_id.nextval(OUT:xnext_no); :
All Rights Reserved. Copyright (C) 2007, Hitachi, Ltd.