1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle Built−in Packages- P46 potx

5 194 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 86,66 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

In the following procedure, the printer_lockname variable holds the name of a lock being used to serialize access to a printer: PROCEDURE get_printer_lock lock_status_OUT OUT INTEGER

Trang 1

,lockhandle => temp_lockhandle);

/*

|| add to end of lockhandle_tbl

*/

temp_index := lockhandle_tbl.LAST+1;

lockhandle_tbl(temp_index).handle := temp_lockhandle;

lockhandle_tbl(temp_index).name := lockname_IN;

END IF;

RETURN temp_lockhandle;

END lockhandle;

The lockhandle function alone is enough to make using named locks much easier It relieves the programmer

of having to create lockhandle variables for each named lock and also guarantees that the

ALLOCATE_UNIQUE procedure is called only once per named lock New named locks can be used

immediately without coding supporting routines, as these are handled generically in the function

Furthermore, the lockhandle function can be invoked directly in calls to REQUEST or CONVERT In the following procedure, the printer_lockname variable holds the name of a lock being used to serialize access to

a printer:

PROCEDURE get_printer_lock

(lock_status_OUT OUT INTEGER)

IS

BEGIN

lock_status_OUT := DBMS_LOCK.REQUEST

(dblock.lockhandle(printer_lockname));

END get_printer_lock;

4.1.4.1.2 get_lock_TF function

Applications using DBMS_LOCK usually must check return values from calls to the REQUEST or

CONVERT functions to determine if access to the locked resource has been acquired The dblock package includes a function called get_lock_TF, which takes a lockname and lock mode as IN parameters and returns the Boolean value TRUE if the named lock has been acquired in the desired mode Using get_lock_TF, we can write code like the following:

IF dblock.get_lock_TF

(printer_lockname,DBMS_LOCK.x_mode)

THEN

/* invoke print routine here */

ELSE

/* cannot print, tell user to try later */

END IF;

Code like this is far easier to understand and maintain than code that calls DBMS_LOCK programs directly All the complexity of using DBMS_LOCK is eliminated; the program merely calls get_lock_TF and proceeds directly to appropriate logic based on the return value Here is the body of get_lock_TF:

/* Filename on companion disk: dblock.sql */*

FUNCTION get_lock_TF

(lockname_IN IN lockname_var%TYPE

,mode_IN IN INTEGER := DBMS_LOCK.x_mode

,timeout_IN IN INTEGER := 1

,release_on_commit_TF IN BOOLEAN := FALSE)

RETURN BOOLEAN

IS

call_status INTEGER;

/* handle for the named lock */

temp_lockhandle lockhandle_var%TYPE := lockhandle(lockname_IN);

Trang 2

BEGIN

call_status := DBMS_LOCK.REQUEST

(lockhandle => temp_lockhandle

,lockmode => mode_IN

,timeout => timeout_IN

,release_on_commit => release_on_commit_TF

);

/*

|| if lock already owned, convert to requested mode

*/

IF call_status = 4

THEN

call_status := DBMS_LOCK.CONVERT

(lockhandle => temp_lockhandle

,lockmode => mode_IN

,timeout => timeout_IN

);

END IF;

RETURN (call_status = 0);

END get_lock_TF;

Notice that get_lock_TF first calls REQUEST and then CONVERT if the lock is already owned This relieves the programmer of yet another bit of housekeeping, and the return value accurately reflects whether the lock is owned in the requested mode The temp_lockhandle variable is used in the calls to DBMS_LOCK programs

to avoid calling the lockhandle function more than once

4.1.4.1.3 The committed_TF and release functions

The dblock package also includes a procedure called release, which releases a named lock, and a function called committed_TF The latter demonstrates using the release_on_commit parameter of the REQUEST function to determine whether a COMMIT has taken place in the session The body of committed_TF looks like this:

/* Filename on companion disk: dblock.sql */*

/* used by committed_TF, unique to each session */

commit_lockname lockname_var%TYPE :=

DBMS_SESSION.UNIQUE_SESSION_ID;

FUNCTION committed_TF RETURN BOOLEAN

IS

call_status INTEGER;

BEGIN

/* get unique lock, expire in one day */

call_status := DBMS_LOCK.REQUEST

(lockhandle =>

lockhandle(commit_lockname,86400)

,lockmode => DBMS_LOCK.x_mode

,timeout => 0

,release_on_commit => TRUE);

RETURN (call_status = 0);

END committed_TF;

The committed_TF function uses a named lock called commit_lockname that is unique to each session, having been initialized by calling DBMS_SESSION.UNIQUE_SESSION_ID It then calls

DBMS_LOCK.REQUEST to acquire an exclusive lock on commit_lockname, making sure to specify TRUE for the release_on_commit parameter Once the lock has been acquired initially, the success of subsequent calls indicates that the lock has been released, and thus a COMMIT (or ROLLBACK) has taken place The function is probably not that useful in practice, but it makes a nice academic exercise

Trang 3

4.1.4.2 Using locks to signal service availability

One way in which DBMS_LOCK can be usefully employed is to indicate the availability of service programs

to database sessions The basic steps are quite simple:

1

Assign specific locks to the server and/or each service provided

2

The server process holds the lock(s) in exclusive mode when services are available

3

Client programs request the lock to determine service availability

To make this more concrete, the following code fragments might be part of a package used to coordinate access to a computation server called calcman:

PACKAGE calcman

IS

/* the actual service provider program */

PROCEDURE calcman_driver;

/* function called by clients to determine availability */

FUNCTION calcman_available RETURN BOOLEAN;

END calcman;

PACKAGE BODY calcman

IS

/* lock name used to flag service availability */

calcman_lockname VARCHAR2(100):= 'CALCMAN_LOCK';

PROCEDURE calcman_driver

IS

BEGIN

/*

|| get the special lock in exclusive mode

*/

IF dblock.get_lock_TF

(lockname_IN => calcman_lockname

,mode_IN => DBMS_LOCK.x_mode

,timeout_IN => 1

,release_on_commit_TF => FALSE)

THEN

/*

|| execute the service loop here, which probably

|| involves listening on a database pipe for

|| service requests and sending responses on pipes

*/

/*

|| loop forever and process calc requests

*/

WHILE NOT terminate_TF

LOOP

receive_unpack_calc_request

(timeout_IN => DBMS_PIPE.maxwait

,request_rec_OUT=> request_rec

,return_code_OUT => temp_return_code);

IF temp_return_code != 0

THEN

DBMS_PIPE.PURGE(request_pipe);

ELSE

Trang 4

END IF;

END LOOP;

ELSE

/* service is already running in another process, exit */

RETURN;

END IF:

END calcman_driver;

FUNCTION calcman_available RETURN BOOLEAN

IS

got_lock BOOLEAN;

BEGIN

got_lock := dblock.get_lock_TF

(lockname => calcman_lockname

,mode_IN => DBMS_LOCK.sx_mode

,timeout_IN => 0

,release_on_commit_TF => TRUE);

/*

|| do not hold lock, this could conflict with

|| starting service

*/

dblock.release(calcman_lockname);

/* failure to get lock indicates server available */

RETURN NOT got_lock;

END calcman_available;

END calcman;

The calcman_driver procedure grabs and holds the lock as long as it is executing If the lock is not available within one second, the procedure is already running in another session and exits silently in the current session Thus, the lock ensures that only one calcman_driver will be executing at any time Note the importance of not releasing the lock at COMMIT, ensuring that the lock is held as long as the service process is alive The service can make itself unavailable at any time by simply releasing the lock

The service that calcman_driver provides is not specified in the previous code fragments It could be a

complex calculation requiring large PL/SQL tables for which the overhead of having all users execute the calculation individually is too great Or it could be connected to an external service routine of some kind A fuller discussion of how to implement such service procedures using database pipes can be found in Chapter

3, Intersession Communication.

Client programs call the calcman_available function to determine whether the server is executing and

providing its computation services The function attempts to get the lock and, if it succeeds, this indicates that the service is not available The lock is requested in shared mode exclusive; as a consequence, concurrent calls to the get_lock_TF function from different sessions may all succeed and indicate unavailability If the lock is requested in exclusive mode, there is a chance that simultaneous execution of the function by two users could falsely indicate to one user that the service is available The calcman_available function also releases the lock immediately to keep it from interfering with the calcman_driver program, which is attempting to secure the lock

3.2 DBMS_ALERT:

Broadcasting Alerts to

Users

4.2 DBMS_TRANSACTION:

Interfacing to SQL Transaction Statements

Trang 5

Copyright (c) 2000 O'Reilly & Associates All rights reserved.

Ngày đăng: 07/07/2014, 00:20