In a traditional auction, this happens because items are auctioned off serially, so bids can only be placed on the current item.. Professional data modelers may wince, but I came up with
Trang 13.2.2.7.1 Exceptions
This program does not raise any package exceptions The program will raise an ORA−20000 exception for specific error conditions, with message text indicating the error as follows:
ORU−10019
Error: n on lock request
ORU−10023
Lock request error; status: n
ORU−10037
Attempting to wait on uncommitted signal from same session
3.2.2.7.2 Restrictions
Note the following restrictions on WAITONE:
•
The message parameter is limited to 1800 bytes in length
•
The WAITONE procedure cannot be called in SQL
3.2.2.7.3 Example
This example waits specifically on the EMP_INSERT alert and updates the status when it is signaled:
DECLARE
alert_msg VARCHAR2(1800);
alert_status INTEGER;
BEGIN
DBMS_ALERT.WAITONE('EMP_INSERT', alert_msg, alert_status, 300);
IF alert_status = 1
THEN
DBMS_OUTPUT.PUT_LINE('timed out');
ELSE
UPDATE emp SET status = 'REGISTERED'
WHERE empid := alert_msg;
DBMS_OUTPUT.PUT_LINE('employee registered');
END IF;
END;
/
3.2.3 DBMS_ALERT Examples
The DBMS_ALERT package is a good example of how you can build higher−level functionality out of lower−level built−ins Both the DBMS_LOCK and DBMS_PIPE packages are used extensively in the
implementation of DBMS_ALERT
NOTE: If you have an old Version 7.1 installation of Oracle, you can check out dbmsalrt.sql
to see exactly how this is done, since the code is not wrapped
Trang 2An important feature of the alerting mechanism in DBMS_ALERT is that it is transaction−based This means that alerts will be sent to registered sessions only if and when the signaling session issues a COMMIT If the signaler issues a ROLLBACK instead, the alerts will not be sent Applications that are interested only in real changes to data in the database will benefit from using transaction−based alerts Applications that need to signal other sessions regardless of transaction boundaries or data modifications (like debuggers or auditing monitors) will probably need to use DBMS_PIPE instead of DBMS_ALERT
What kind of application might actually need to be alerted to changes in data? The classic example given in the Oracle documentation is a continuous graphical display of data extracted from some table Pulling data from the table at set intervals using a polling mechanism can be very inefficient For one thing, the data may not have changed since the last pull, so a refresh is not really necessary Also, if the application is separated from the database by a network (as it most likely would be), then the overhead of redundant data extraction is multiplied In this example, the application could use DBMS_ALERT to suspend itself and wait for a signal to awaken and pull new data for the display The signal will be received only when data in the table has actually been modified (i.e., a new pull is truly necessary)
3.2.3.1 The online auction
Well, I wanted to do something new and original I spent some time thinking about other examples for using DBMS_ALERT Finally, I realized that I had participated in a perfect application for this technology many times already: an online auction During an auction (especially a virtual one over a computer network), it is important to know when an item you have a bidding interest in has been bid upon In a traditional auction, this happens because items are auctioned off serially, so bids can only be placed on the current item In an online auction, the participants are not in a room together, and the auction itself typically takes longer than a
traditional auction Also, it is desirable to auction multiple items simultaneously, taking advantage of the virtual nature of the auction An auction application that notifies participants of bidding activity relevant (to them) would relieve them of having to constantly monitor their screens to stay abreast of the auction Bidding could take place simultaneously on multiple items since users interested in those items would automatically be notified of new bids
3.2.3.2 The auction schema
The online auction was perfect for DBMS_ALERT, so I set about to prove the concept First, I needed a basic schema Professional data modelers may wince, but I came up with the following:
Object Type Description
AUCTION_ITEMS TABLE Items up for auction
BIDS TABLE Bids on auction items
HIGH_BIDS VIEW High bids by item
These objects are created by the auction.ddl script, reproduced as follows:
/* Filename on companion disk: auction.ddl */*
rem *********************************************************
rem AUCTION.DDL
rem
rem Creates objects used in the "online auction" example
rem for the DBMS_ALERT package
rem
rem Auction_items −− table of items being auctioned
rem Bids −− table of bids placed on items
rem High_bids −− view showing the current high bids on
rem items and who placed them
rem
rem Author: John Beresniewicz, Savant Corp
rem
Trang 3rem 12/07/97: created
rem *********************************************************
DROP VIEW high_bids;
DROP TABLE bids;
DROP TABLE auction_items;
CREATE TABLE auction_items
(id VARCHAR2(20) NOT NULL PRIMARY KEY
,description VARCHAR2(200) NOT NULL
,min_bid NUMBER NOT NULL
,curr_bid NUMBER
,status VARCHAR2(10)
CONSTRAINT valid_status
CHECK (status IN ('OPEN','CLOSED') )
);
CREATE TABLE bids
(bidder VARCHAR2(30)
,item_id VARCHAR2(20)
REFERENCES auction_items(id)
ON DELETE CASCADE
,bid NUMBER NOT NULL
);
CREATE OR REPLACE VIEW high_bids
(item_id
,item_desc
,bidder
,high_bid)
AS
SELECT
BID.item_id
,AI.description
,BID.bidder
,BID.bid
FROM
bids BID
,auction_items AI
WHERE
BID.item_id = AI.id
AND BID.bid = (SELECT MAX(bid)
FROM bids B2
WHERE BID.item_id = B2.item_id)
/
The AUCTION_ITEMS table contains an identifier and a description of each auction item There are also columns for the minimum bid, status, and current high bid This latter is really redundant with information derived in the HIGH_BIDS view, but this denormalization makes for a more interesting example
The BIDS table holds the bidding activity Each bid is a bid on an auction_item by a user for a specified amount Originally, I had a BIDDERS table to track the auction participants, and this would likely be
necessary for a real−world application However, to simplify the example I decided to use the Oracle session username to identify bidders Thus, there is an assumption that the online auction users will all be connected using unique usernames The BIDS table also has a complex integrity constraint, which states that all bids must exceed the previous high bid for the same item (this is, after all, how an auction works) An additional constraint is that no bids may be updated or deleted from the table These constraints are enforced by database triggers discussed later
The HIGH_BIDS view selects the highest bid for each item along with the item's description and the bidder who made the bid The auction application's GUI component can make use of this view to display current bidding levels for all items
Trang 43.2.3.3 Auction system requirements
Some basic requirements of the online auction application are as follows:
•
Enforce the complex integrity constraint on the BIDS table
•
Enforce the noưupdate, noưdelete rule on the BIDS table
•
Update the CURR_BID column of AUCTION_ITEMS for new bids
•
Inform bidders when they have been outbid on an item
•
Inform bidders when an item is closed from further bidding
There is certainly more than one way to satisfy these requirements, especially the data integrity constraints on the two tables I decided to implement a combination of database triggers and a package called auction The database triggers enforce some data integrity constraints and signal changes to interested bidders using
DBMS_ALERT.SIGNAL A procedure called place_bid is responsible for placing bids on items, making sure that the complex integrity constraint is satisfied, and that the bidder is registered to receive notice of any bidding or status changes on the item Another packaged procedure, called watch_bidding, demonstrates how
an application might use DBMS_ALERT.WAITANY to be alerted for any bidding activity of interest to the user
One immediate issue to address is what the alert names should be The auction_items.id column seems a natural option since all alerts will concern a specific item
3.2.3.4 Integrity constraint triggers
Here are the triggers for the auction_items and bids tables:
/* Filename on companion disk: auction2.sql */*
CREATE OR REPLACE TRIGGER auction_items_ARU
AFTER UPDATE ON auction_items
FOR EACH ROW
BEGIN
/*
|| trigger enforces no update of item_id and also
|| signals an alert when status changes
*/
IF UPDATING ('ITEM_ID')
THEN
RAISE_APPLICATION_ERROR(ư20000, 'Cannot update item id');
ELSIF UPDATING ('STATUS') AND (:NEW.status != :OLD.status)
THEN
/* send new status on as the alert message */
DBMS_ALERT.SIGNAL(:NEW.id, :NEW.status);
END IF;
END auction_items_ARU;
/
CREATE OR REPLACE TRIGGER bids_ARIUD
AFTER INSERT OR UPDATE OR DELETE ON bids
FOR EACH ROW
Trang 5/*
|| enforce all bids are final rule
*/
IF UPDATING OR DELETING
THEN
RAISE_APPLICATION_ERROR
(ư20001, 'Cannot update or delete, all bids final!');
ELSE
/*
|| signal alert on item, send bidder name as message
*/
DBMS_ALERT.SIGNAL(:NEW.item_id, :NEW.bidder);
END IF;
END bids_ARIUD;
/
The triggers enforce the basic integrity rules that auction_items.id is a nonưupdatable column and that rows in the BIDS table cannot be updated or deleted More importantly, they signal database alerts to registered sessions that auction data has changed using DBMS_ALERT.SIGNAL The trigger on auction items signals status changes for items Note the additional check requiring that :NEW.status be different from :OLD.status
in order for the alert to be signaled Also note that the item id is used as the alert name and that the new item status is passed as the alert's message The trigger on BIDS signals the alert named by the item id and passes the bidder's name as the message The use of the message parameter with the alerts allows the alert receiver to implement a contextưsensitive response to the alert
By the way, my naming convention for triggers has the table name suffixed by a string like [ A|B ][ R|S ][ I|U|D ] where:
•
A or B indicates an AFTER or BEFORE trigger
•
R or S indicates ROW or STATEMENT level trigger
•
I and/or U and/or D indicates an INSERT or UPDATE or DELETE
3.2.3.5 The auction package
The rest of the online auction requirements are implemented in the auction package Here is the package specification:
/* Filename on companion disk: auction1.sql */*
CREATE OR REPLACE PACKAGE auction
/*
|| Implements a simple interactive bidding system
|| using DBMS_ALERT to keep bidders informed
|| of activity in items they are interested in.
||
|| The item_id is used as the ALERT name for the
|| item.
||
|| Author: John Beresniewicz, Savant Corp
||
|| 12/07/97: created
||
|| Compilation Requirements:
||
|| EXECUTE on DBMS_ALERT