44
Jerry Post Jerry Post McGraw-Hill/Irwin Copyright © 2005 by The McGraw-Hill Companies, Inc. All rights reserved. Database Management Database Management Systems Systems Chapter 7 Database Integrity and Transactions

Jerry Post McGraw-Hill/Irwin Copyright © 2005 by The McGraw-Hill Companies, Inc. All rights reserved. Database Management Systems Chapter 7 Database Integrity

  • View
    215

  • Download
    1

Embed Size (px)

Citation preview

Jerry PostJerry Post

McGraw-Hill/Irwin Copyright © 2005 by The McGraw-Hill Companies, Inc. All rights reserved.

Database Management SystemsDatabase Management Systems

Chapter 7

Database Integrity and

Transactions

2

DDAATTAABBAASSEE

DBMS

Programming Environment

Create code(1) Within the query system

(2) In forms and reports

(3) Hosted in external programs

Tables

Forms &Reports

Queries

If (Click) ThenMsgBox . . .

End If

If ( . . ) Then SELECT . . .

Else . . .UPDATE . . .

End If

C++

ExternalProgram

if (. . .) { // embed SQL SELECT …}

(2)

(1)

(3)

3

DDAATTAABBAASSEE

User-Defined Function

CREATE FUNCTION EstimateCosts (ListPrice Currency, ItemCategory VarChar)

RETURNS CurrencyBEGIN

IF (ItemCategory = ‘Clothing’) THENRETURN ListPrice * 0.5

ELSERETURN ListPrice * 0.75

END IFEND

4

DDAATTAABBAASSEE

Function to Perform Conditional Update

CREATE FUNCTION IncreaseSalary(EmpID INTEGER, Amt CURRENCY)

RETURNS CURRENCYBEGIN

IF (Amt > 50000) THENRETURN -1 -- error flag

ENDUPDATE Employee SET Salary = Salary + AmtWHERE EmployeeID = EmpID;RETURN Amt

END

5

DDAATTAABBAASSEE

Looking Up Data

CREATE FUNCTION IncreaseSalary(EmpID INTEGER, Amt CURRENCY)

RETURNS CURRENCYDECLARE

CURRENCY MaxAmount;BEGIN

SELECT MaxRaise INTO MaxAmountFROM CompanyLimitsWHERE LimitName = ‘Raise’;

IF (Amt > 50000) THENRETURN -1 -- error flag

ENDUPDATE Employee SET Salary = Salary + AmtWHERE EmployeeID = EmpID;RETURN Amt;

END

6

DDAATTAABBAASSEE

Data Trigger Events

Oracle additions: Tables ALTER, CREATE, DROP User LOGOFF, LOGON Database SERVERERROR, SHUTDOWN, STARTUP

INSERT

DELETE

UPDATE

BEFORE AFTER

7

DDAATTAABBAASSEE

Statement v. Row Triggers

UPDATE EmployeeSET Salary = Salary + 10000WHERE EmployeeID=442 OR EmployeeID=558

SQL

time

Before UpdateOn table

After UpdateOn table

Before UpdateRow 442

After UpdateRow 442

UpdateRow 442

… other rows

Triggers for overall table

Triggers for each row

8

DDAATTAABBAASSEE

Data Trigger Example

CREATE TRIGGER LogSalaryChangesAFTER UPDATE OF Salary ON EmployeeREFERENCING OLD ROW as oldrow

NEW ROW AS newrowFOR EACH ROW

INSERT INTO SalaryChanges (EmpID, ChangeDate, User, OldValue, NewValue)VALUES (newrow.EmployeeID, CURRENT_TIMESTAMP,CURRENT_USER, oldrow.Salary, newrow.Salary);

9

DDAATTAABBAASSEE

Canceling Data Changes in Triggers

CREATE TRIGGER TestDeletePresidentBEFORE DELETE ON EmployeeREFERENCING OLD ROW AS oldrowFOR EACH ROW

WHEN (oldrow.Title = ‘President’)SIGNAL _CANNOT_DELETE_PRES;

10

DDAATTAABBAASSEE

Cascading Triggers

Sale(SaleID, SaleDate, …)

OrderItem(OrderID, ItemID, Quantity, …)

Order(OrderID, OrderDate, …)

Inventory(ItemID, QOH, …)

SaleItem(SaleID, ItemID, Quantity, …)

AFTER INSERTUPDATE InventorySET QOH = QOH – newrow.Quantity

AFTER UPDATEWHEN newrow.QOH < newrow.Reorder

INSERT {new order}INSERT {new OrderItem}

11

DDAATTAABBAASSEE

Trigger LoopEmployee(EID, Salary)

BonusPaid(EID, BonusDate, Amount)

StockOptions(EID, OptionDate, Amount, SalaryAdj)

AFTER UPDATEIF newrow.Salary > 100000 THEN

Add BonusEND

AFTER UPDATE Or INSERTIF newrow.Bonus > 50000 THEN

Reduce BonusAdd Options

END

AFTER UPDATE Or INSERTIF newrow.Amount > 100000 THEN

Reduce SalaryEND

12

DDAATTAABBAASSEE

Transactions Some transactions result in multiple

changes. These changes must all be

completed successfully, or the group must fail.

Protection for hardware and communication failures.

example: bank customer transfers money from savings account to checking account.

Decrease savings balance Increase checking balance Problem if one transaction and

machine crashes.

Possibly: give users a chance to reverse/undo a transaction.

Performance gain by executing transactions as a block.

Savings Accounts

Inez: 5340.924340.92

Checking Accounts

Inez: 1424.27

Transaction1. Subtract $1000 from savings.

(machine crashes)2. Add $1000 to Checking.

(money disappears)

$1000

13

DDAATTAABBAASSEE

Defining Transactions

The computer needs to be told which changes must be grouped into a transaction.Turn on transaction processing.Signify a transaction start.Signify the end.

Success: save all changesFailure: cancel all changes

Must be set in module codeCommitRollback

14

DDAATTAABBAASSEE

SQL Transaction CodeCREATE FUNCTION TransferMoney(Amount Currency, AccountFrom Number,

AccountTo Number) RETURNS NUMBERcurBalance Currency;BEGIN

DECLARE HANDLER FOR SQLEXCEPTIONBEGIN

ROLLBACK;Return -2; -- flag for completion error

END;START TRANSACTION; -- optionalSELECT CurrentBalance INTO curBalance FROM Accounts WHERE (AccountID = AccountFrom);IF (curBalance < Amount) THEN

RETURN -1; -- flag for insufficient fundsEND IFUPDATE Accounts SET CurrentBalance = CurrentBalance – AmountWHERE AccountID = AccountFrom;UPDATE AccountsSET CurrentBalance = CurrentBalance + AmountWHERE AccountID = AccountTo;COMMIT;RETURN 0; -- flag for success

END;

15

DDAATTAABBAASSEE

SAVEPOINT

START TRANSACTION;SELECT …UPDATE …SAVEPOINT StartOptional;UPDATE …UPDATE …If error THEN

ROLLBACK TO SAVEPOINT StartOptional;END IFCOMMIT;

time

startRequired elements

SAVEPOINTStartOptional

Risky stepscommit

Partial rollback

16

DDAATTAABBAASSEE

Concurrent Access Concurrent Access

Multiple users or processes changing the same data at the same time.

Final data will be wrong!

Force sequentialLockingDelayed, batch updates

Two processesReceive payment ($200)Place new order ($150)

Initial balance $800Result should be $800 -

200 + 150 = $750 Interference result is

either $600 or $950

ID BalanceJones $800

$600$950

Customers

1) Read balance 8002) Subtract pmt -2004) Save new bal. 600

3) Read balance 8005) Add order 1506) Write balance 950

Receive Payment Place New Order

17

DDAATTAABBAASSEE

Pessimistic Locks: Serialization

One answer to concurrent access is to prevent it. When a transaction needs to alter data, it places a

SERIALIZABLE lock on the data used, so no other transactions can even read the data until the first transaction is completed.

ID BalanceJones $800

$600

Customers

1) Read balance 8002) Subtract pmt -2004) Save new bal. 600

3) Read balanceReceive error message that it is locked.

Receive Payment Place New Order

SET TRANSACTION SERIALIZABLE, READ WRITE

18

DDAATTAABBAASSEE

SQL Pessimistic Lock

CREATE FUNCTION ReceivePayment (AccountID NUMBER, Amount Currency) RETURNS NUMBER

BEGINDECLARE HANDLER FOR SQLEXCEPTIONBEGIN

ROLLBACK;RETURN -2;

ENDSET TRANSACTION SERIALIZABLE, READ WRITE;UPDATE AccountsSET AccountBalance = AccountBalance - AmountWHERE AccountNumber = AccountID;COMMIT;RETURN 0;

END

19

DDAATTAABBAASSEE

Deadlock

DeadlockTwo (or more) processes have

placed locks on data and are waiting for the other’s data.

Many solutionsRandom wait timeGlobal lock managerTwo-phase commit - messages

Data A Data B

1) Lock Data A3) Wait for Data B

2) Lock Data B4) Wait for Data A

20

DDAATTAABBAASSEE

Lock Manager

ResourceA

ResourceB

ResourceC

ResourceD

ResourceE

Process1 Lock Wait

Process2 Wait Lock

Process3 Lock

Process4 Lock Wait

Process5 Wait

Process6 Wait Lock

Process7 Wait Wait

21

DDAATTAABBAASSEE

Optimistic Locks

Assume that collisions are rare Improved performance, fewer resources Allow all code to read any data (no locks) When code tries to write a new value

Check to see if the existing value is different from the one you were given earlier

If it is different, someone changed the database before you finished, so it is a collision--raise an error

Reread the value and try again

22

DDAATTAABBAASSEE

Optimistic Locks for Simple Update

(1) Read the balance

(2) Add the new order value

(3) Write the new balance

(4) Check for errors

(5) If there are errors, go back to step (1).

23

DDAATTAABBAASSEE

Optimistic Locks with SQLCREATE FUNCTION ReceivePayment (

AccountID NUMBER, Amount Currency) RETURNS NUMBERoldAmount Currency;testEnd Boolean = FALSE;BEGIN

DO UNTIL testEnd = TRUEBEGIN

SELECT Amount INTO oldAmountWHERE AccountNumber = AccountID;…UPDATE AccountsSET AccountBalance = AccountBalance - AmountWHERE AccountNumber = AccountIDAND Amount = oldAmount;COMMIT;IF SQLCODE = 0 and nrows > 0 THEN

testEnd = TRUE;RETURN 0;

END IF-- keep a counter to avoid infinite loops

ENDEND

24

DDAATTAABBAASSEE

ACID Transactions

Atomicity: all changes succeed or fail together. Consistency: all data remain internally consistent

(when committed) and can be validated by application checks.

Isolation: The system gives each transaction the perception that it is running in isolation. There are no concurrent access issues.

Durability: When a transaction is committed, all changes are permanently saved even if there is a hardware or system failure.

25

DDAATTAABBAASSEE

SQL 99/200x Isolation Levels READ UNCOMMITTED

Problem: might read dirty data that is rolled back Restriction: not allowed to save any data

READ COMMITTED Problem: Second transaction might change or delete data Restriction: Need optimistic concurrency handling

REPEATABLE READ Problem: Phantom rows

SERIALIZABLE Provides same level of control as if all transactions were run

sequentially. But, still might encounter locks and deadlocks

26

DDAATTAABBAASSEE

Phantom RowsSELECT SUM(QOH)FROM InventoryWHERE Price BETWEEN 10 and 20

UPDATE InventorySET Price = Price/2WHERE …

ItemID QOH Price

111 5 15

113 6 7

117 12 30

118 4 12

119 7 22

120 8 17

Included in first query

SELECT SUM(QOH)FROM InventoryWHERE Price BETWEEN 10 and 20

Additional rows will be included in the second query

27

DDAATTAABBAASSEE

Generated Keys

Create an order for a new customer:

(1) Create new key for CustomerID(2) INSERT row into Customer(3) Create key for new OrderID(4) INSERT row into Order

Customer Table

CustomerID, Name, …

Order Table

OrderID, CustomerID, …

28

DDAATTAABBAASSEE

Methods to Generate Keys

1. The DBMS generates key values automatically whenever a row is inserted into a table.

Drawback: it is tricky to get the generated value to use it in a second table.

2. A separate key generator is called by a programmer to create a new key for a specified table.

Drawback: programmers have to write code to generate a key for every table and each row insertion.

Overall drawbacks: neither method is likely to be transportable. If you change the DBMS, you will have to rewrite the procedures to generate keys.

29

DDAATTAABBAASSEE

Auto-Generated Keys

Create an order for a new customer:

(1) INSERT row into Customer(2) Get the key value that was generated(3) Verify the key value is correct. How?(4) INSERT row into Order

Major problem:Step 2 requires that the DBMS return the key value that was most recently generated. How do you know it is the right value? What happens if two transactions generate keys at almost the same time on the same table?

30

DDAATTAABBAASSEE

Key-Generation Routine

Create an order for a new customer:

(1) Generate a key for CustomerID(2) INSERT row into Customer(3) Generate a key for OrderID(4) INSERT row into Order

This method ensures that unique keys are generated, and that you can use the keys in multiple tables because you know the value. But, none of it is automatic. It always requires procedures and sometimes data triggers.

31

DDAATTAABBAASSEE

Database Cursors

PurposeTrack through table or

query one row at a time.Data cursor is a pointer to

active row.

Why?Performance.SQL cannot do everything.

Complex calculations.Compare multiple rows.

Year Sales1998 104,3211999 145,9982000 276,0042001 362,736

1998 104,3211999 145,9982000 276,0042001 362,736

32

DDAATTAABBAASSEE

Database Cursor Program StructureDECLARE cursor1 CURSOR FOR

SELECT AccountBalanceFROM Customer;

sumAccount, balance Currency;SQLSTATE Char(5);BEGIN

sumAccount = 0;OPEN cursor1;WHILE (SQLSTATE = ‘00000’)BEGIN

FETCH cursor1 INTO balance;IF (SQLSTATE = ‘00000’) THEN

sumAccount = sumAccount + balance;END IF

ENDCLOSE cursor1;-- display the sumAccount or do a calculation

END

33

DDAATTAABBAASSEE

Cursor Positioning with FETCH

DECLARE cursor2 SCROLL CURSOR FORSELECT …OPEN cursor2;FETCH LAST FROM cursor2 INTO …Loop…

FETCH PRIOR FROM cursor2 INTO …End loopCLOSE cursor2;

FETCH positioning options:FETCH NEXT next rowFETCH PRIOR prior rowFETCH FIRST first rowFETCH LAST last rowFETCH ABSOLUTE 5 fifth rowFETCH RELATIVE -3 back 3 rows

34

DDAATTAABBAASSEE

Problems with Multiple Users

Name SalesAlice 444,321Carl 254,998Donna 652,004Ed 411,736

Original Data

Name SalesAlice 444,321Bob 333,229Carl 254,998Donna 652,004Ed 411,736

Modified Data

New row isadded--whilecode is running.

The SQL standard can prevent this problem with the INSENSITIVE option:

DECLARE cursor3 INSENSITIVE CURSOR FOR …

But, this is an expensive approach, because the DBMS usually makes a copy of the data. Instead, avoid moving backwards.

35

DDAATTAABBAASSEE

Changing Data with Cursors

Year Sales Gain

2000 151,039

2001 179,332

2002 195,453

2003 221,883

2004 223,748

DECLARE cursor1 CURSOR FORSELECT Year, Sales, GainFROM SalesTotalORDER BY YearFOR UPDATE OF Gain;priorSales, curYear, curSales, curGainBEGIN

priorSales = 0;OPEN cursor1;Loop:

FETCH cursor1 INTO curYear, curSales, curGainUPDATE SalesTotalSET Gain = Sales – priorSalesWHERE CURRENT OF cursor1;priorSales = curSales;

Until end of rowsCLOSE cursor1;COMMIT;

END

36

DDAATTAABBAASSEE

Dynamic Parameterized Cursor Queries

DECLARE cursor2 CURSOR FORSELECT ItemID, Description, PriceFROM InventoryWHERE Price < :maxPrice;maxPrice Currency;BEGIN

maxPrice = … -- from user or other queryOPEN cursor2; -- runs query with current valueLoop:

-- Do something with the rows retrievedUntil end of rowsCLOSE cursor2;

END

Parameters enable you to control the rows retrieved dynamically from within the procedure code. The value is applied when the cursor is opened.

37

DDAATTAABBAASSEE

Sally’s Pet Store Inventory

Inventory method 1: calculate the current quantity on hand by totaling all purchases and sales every time the total is needed.Drawback: performance

Inventory method 2: keep a running balance in the inventory table and update it when an item is purchased or sold.Drawback: tricky code

Also, you need an adjustment process for “inventory shrink”

38

DDAATTAABBAASSEE

Inventory QuantityOnHand

ItemIDDescriptionQuantityOnHandListPriceCategory

Merchandise

Add items purchased

Subtract items sold

Adjust for shrink

SaleIDItemIDQuantitySalePrice

SaleItem

39

DDAATTAABBAASSEE

Inventory Events For a new sale, a row is added to

the SaleItem table. A sale or an item could be

removed because of a clerical error or the customer changes his or her mind. A SaleItem row will be deleted.

An item could be returned, or the quantity could be adjusted because of a counting error. The Quantity is updated in the SaleItem table.

An item is entered incorrectly. ItemID is updated in the SaleItem table.

SaleIDItemIDQuantitySalePrice

SaleItem

(1) Add a row.

(2) Delete a row.

(3) Update Quantity.

(4) Update ItemID.

40

DDAATTAABBAASSEE

New Sale: Insert SaleItem Row

CREATE TRIGGER NewSaleItemAFTER INSERT ON SaleItemREFERENCING NEW ROW AS newrowFOR EACH ROW

UPDATE MerchandiseSET QuantityOnHand = QuantityOnHand – newrow.QuantityWHERE ItemID = newrow.ItemID;

41

DDAATTAABBAASSEE

Delete SaleItem Row

CREATE TRIGGER DeleteSaleItemAFTER DELETE ON SaleItemREFERENCING OLD ROW AS oldrowFOR EACH ROW

UPDATE MerchandiseSET QuantityOnHand = QuantityOnHand + oldrow.QuantityWHERE ItemID = oldrow.ItemID;

42

DDAATTAABBAASSEE

Quantity Changed Event

CREATE TRIGGER UpdateSaleItemAFTER UPDATE ON SaleItemREFERENCING OLD ROW AS oldrow

NEW ROW AS newrowFOR EACH ROW

UPDATE MerchandiseSET QuantityOnHand = QuantityOnHand

+ oldrow.Quantity – newrow.QuantityWHERE ItemID = oldrow.ItemID;

43

DDAATTAABBAASSEE

ItemID or Quantity Changed Event

CREATE TRIGGER UpdateSaleItemAFTER UPDATE ON SaleItemREFERENCING OLD ROW AS oldrow

NEW ROW AS newrowFOR EACH ROWBEGIN

UPDATE MerchandiseSET QuantityOnHand = QuantityOnHand + oldRow.QuantityWHERE ItemID = oldrow.ItemID;

UPDATE MerchandiseSET QuantityOnHand = QuantityOnHand – newRow.QuantityWHERE ItemID = newrow.ItemID;COMMIT;

END

Database Management SystemsDatabase Management Systems

McGraw-Hill/Irwin Copyright © 2005 by The McGraw-Hill Companies, Inc. All rights reserved.

End of

Chapter 7