Beginning Microsoft SQL Server 2008 ... - S3 Tech Training
Beginning Microsoft SQL Server 2008 ... - S3 Tech Training Beginning Microsoft SQL Server 2008 ... - S3 Tech Training
Chapter 14: Transactions and Locks indeed be set to –25, even though it logically appeared that we prevented this through the use of our IF statement. We can prevent this problem in only two ways: ❑ Create a CHECK constraint and monitor for the 547 Error. ❑ Set our isolation level to be REPEATABLE READ or SERIALIZABLE. The CHECK constraint seems fairly obvious. The thing to realize here is that you are taking something of a reactive rather than a proactive approach with this method. Nonetheless, in most situations we have a potential for non-repeatable reads, so this would be my preferred choice in most circumstances. We’ll be taking a full look at isolation levels shortly, but for now, suffice it to say that there’s a good chance that setting it to REPEATABLE READ or SERIALIZABLE is going to cause you as many headaches as it solves (or more). Still, it’s an option. Phantoms 436 No, we’re not talking the of the Opera kind here — what we’re talking about are records that appear mysteriously, as if unaffected by an UPDATE or DELETE statement that you’ve issued. This can happen quite legitimately in the normal course of operating your system and doesn’t require any kind of elaborate scenario to illustrate. Here’s a classic example of how this happens. Let’s say you are running a fast food restaurant. If you’re running a typical establishment of that kind, you probably have a fair number of employees working at the minimum wage as defined by the government. The government has just decided to raise the minimum wage from $6.50 to $7.50 per hour, and you want to run an UPDATE on the EmployeePayHistory table to move anyone making less than $7.50 per hour up to the new minimum wage. “No problem,” you say, and you issue the rather simple statement: UPDATE HumanResources.EmployeePayHistory SET HourlyRate = 7.50 WHERE HourlyRate < 7.50; ALTER TABLE Employees ADD ckWage CHECK (HourlyRate >= CONSTRAINT 7.50); GO That was a breeze, right? Wrong! Just for illustration, we’re going to say that you get an error message back: Msg 547, Level 16, State 1, Line 1 ALTER TABLE statement conflicted with COLUMN CHECK constraint ‘ckWage’. The conflict occurred in database ‘AdventureWorks2008’, table ‘EmployeePayHistory’, column ‘Rate’. So you run a quick SELECT statement checking for values below $7.50, and sure enough you find one. The question is likely to come rather quickly, “How did that get there? I just did the UPDATE that should have fixed that!” You did run the statement, and it ran just fine — you just got a phantom. The instances of phantom reads are rare and require just the right circumstances to happen. In short, someone performed an INSERT statement at the very same time your UPDATE was running. Since it was an entirely new row, it didn’t have a lock on it and it proceeded just fine.
The only cure for this is setting your transaction isolation level to SERIALIZABLE, in which case any updates to the table must not fall within your WHERE clause or they will be locked out. Lost Updates Lost updates happen when one update is successfully written to the database, but is accidentally overwritten by another transaction. I can just hear you right about now, “Yikes! How could that happen?” Lost updates can happen when two transactions read an entire record, then one writes updated information back to the record and the other writes updated information back to the record. Let’s look at an example. Let’s say that you are a credit analyst for your company. You get a call that customer X has reached their credit limit and would like an extension, so you pull up their customer information to take a look. You see that they have a credit limit of $5,000 and that they appear to always pay on time. While you’re looking, Sally, another person in your credit department, pulls up customer X’s record to enter a change in the address. The record she pulls up also shows the credit limit of $5,000. At this point, you decide to go ahead and raise customer X’s credit limit to $7,500, and press Enter. The database now shows $7,500 as the credit limit for customer X. Sally now completes her update to the address, but she’s using the same edit screen that you are — that is, she updates the entire record. Remember what her screen showed as the credit limit? $5,000. Oops, the database now shows customer X with a credit limit of $5,000 again. Your update has been lost! The solution to this depends on your code somehow recognizing that another connection has updated your record between when you read the data and when you went to update it. How this recognition happens varies depending on what access method you’re using. Lockable Resources There are six lockable resources for SQL Server, and they form a hierarchy. The higher level the lock, the less granularity it has (that is, you’re choosing a higher and higher number of objects to be locked a cascading type of action just because the object that contains them has been locked). These include, in ascending order of granularity: ❑ Database: The entire database is locked. This happens usually during database schema changes. ❑ Table: The entire table is locked. This includes all the data-related objects associated with that table, including the actual data rows (every one of them) and all the keys in all the indexes associated with the table in question. ❑ Extent: The entire extent is locked. Remember than an extent is made up of eight pages, so an extent lock means that the lock has control of the extent, the eight data or index pages in that extent, and all the rows of data in those eight pages. ❑ Page: All the data or index keys on that page are locked. Chapter 14: Transactions and Locks ❑ Key: There is a lock on a particular key or series of keys in an index. Other keys in the same index page may be unaffected. ❑ Row or Row Identifier (RID): Although the lock is technically placed on the row identifier (an internal SQL Server construct), it essentially locks the entire row. 437
- Page 424 and 425: Chapter 12: Stored Procedures 386 r
- Page 426 and 427: Chapter 12: Stored Procedures 388 -
- Page 428 and 429: Chapter 12: Stored Procedures Note
- Page 430 and 431: Chapter 12: Stored Procedures 392 n
- Page 432 and 433: Chapter 12: Stored Procedures All t
- Page 434 and 435: Chapter 12: Stored Procedures Sproc
- Page 436 and 437: Chapter 12: Stored Procedures When
- Page 438 and 439: Chapter 12: Stored Procedures 400 @
- Page 440 and 441: Chapter 12: Stored Procedures I’d
- Page 442 and 443: Chapter 12: Stored Procedures match
- Page 444 and 445: Chapter 12: Stored Procedures There
- Page 446 and 447: Chapter 12: Stored Procedures 408 f
- Page 449 and 450: 13 User-Defined Functions Well, her
- Page 451 and 452: types!), except for BLOBs, cursors,
- Page 453 and 454: We get back the same set as with th
- Page 455 and 456: AS RETURN (SELECT BusinessEntityID,
- Page 457 and 458: in your relational database. These
- Page 459 and 460: AS BEGIN ( EmployeeID int NOT NULL,
- Page 461 and 462: So, as you can see, we can actually
- Page 463 and 464: Despite being schema-bound, this on
- Page 465 and 466: 14 Transactions and Locks This is o
- Page 467 and 468: we are unable or do not want to com
- Page 469 and 470: Figure 14-1 Data needed Data in cac
- Page 471 and 472: Transaction 4 This transaction wasn
- Page 473: Oops — problem!!! Transaction 2 h
- Page 477 and 478: Exclusive Locks Exclusive locks are
- Page 479 and 480: Also: ❑ The Sch-S is compatible w
- Page 481 and 482: The syntax for switching between th
- Page 483 and 484: As with most things in life, howeve
- Page 485 and 486: purchased. Process 2 records sales;
- Page 487: Chapter 14: Transactions and Locks
- Page 490 and 491: Chapter 15: Triggers the world’s
- Page 492 and 493: Chapter 15: Triggers WITH ENCRYPTIO
- Page 494 and 495: Chapter 15: Triggers FOR|AFTER The
- Page 496 and 497: Chapter 15: Triggers 458 To illustr
- Page 498 and 499: Chapter 15: Triggers 460 IF EXISTS
- Page 500 and 501: Chapter 15: Triggers ❑ Feeding de
- Page 502 and 503: Chapter 15: Triggers Trigger Firing
- Page 504 and 505: Chapter 15: Triggers Like regular t
- Page 506 and 507: Chapter 15: Triggers The COLUMNS_UP
- Page 508 and 509: Chapter 15: Triggers This is the sa
- Page 510 and 511: Chapter 15: Triggers 472 we have th
- Page 512 and 513: Chapter 16: A Brief XML Primer So,
- Page 514 and 515: Chapter 16: A Brief XML Primer Figu
- Page 516 and 517: Chapter 16: A Brief XML Primer Elem
- Page 518 and 519: Chapter 16: A Brief XML Primer ❑
- Page 520 and 521: Chapter 16: A Brief XML Primer 482
- Page 522 and 523: Chapter 16: A Brief XML Primer Name
The only cure for this is setting your transaction isolation level to SERIALIZABLE, in which case any<br />
updates to the table must not fall within your WHERE clause or they will be locked out.<br />
Lost Updates<br />
Lost updates happen when one update is successfully written to the database, but is accidentally overwritten<br />
by another transaction. I can just hear you right about now, “Yikes! How could that happen?”<br />
Lost updates can happen when two transactions read an entire record, then one writes updated information<br />
back to the record and the other writes updated information back to the record. Let’s look at an example.<br />
Let’s say that you are a credit analyst for your company. You get a call that customer X has reached their<br />
credit limit and would like an extension, so you pull up their customer information to take a look. You<br />
see that they have a credit limit of $5,000 and that they appear to always pay on time.<br />
While you’re looking, Sally, another person in your credit department, pulls up customer X’s record to<br />
enter a change in the address. The record she pulls up also shows the credit limit of $5,000.<br />
At this point, you decide to go ahead and raise customer X’s credit limit to $7,500, and press Enter. The<br />
database now shows $7,500 as the credit limit for customer X.<br />
Sally now completes her update to the address, but she’s using the same edit screen that you are — that<br />
is, she updates the entire record. Remember what her screen showed as the credit limit? $5,000. Oops,<br />
the database now shows customer X with a credit limit of $5,000 again. Your update has been lost!<br />
The solution to this depends on your code somehow recognizing that another connection has updated<br />
your record between when you read the data and when you went to update it. How this recognition<br />
happens varies depending on what access method you’re using.<br />
Lockable Resources<br />
There are six lockable resources for <strong>SQL</strong> <strong>Server</strong>, and they form a hierarchy. The higher level the lock, the<br />
less granularity it has (that is, you’re choosing a higher and higher number of objects to be locked a cascading<br />
type of action just because the object that contains them has been locked). These include, in<br />
ascending order of granularity:<br />
❑ Database: The entire database is locked. This happens usually during database schema changes.<br />
❑ Table: The entire table is locked. This includes all the data-related objects associated with that<br />
table, including the actual data rows (every one of them) and all the keys in all the indexes associated<br />
with the table in question.<br />
❑ Extent: The entire extent is locked. Remember than an extent is made up of eight pages, so an<br />
extent lock means that the lock has control of the extent, the eight data or index pages in that<br />
extent, and all the rows of data in those eight pages.<br />
❑ Page: All the data or index keys on that page are locked.<br />
Chapter 14: Transactions and Locks<br />
❑ Key: There is a lock on a particular key or series of keys in an index. Other keys in the same<br />
index page may be unaffected.<br />
❑ Row or Row Identifier (RID): Although the lock is technically placed on the row identifier (an<br />
internal <strong>SQL</strong> <strong>Server</strong> construct), it essentially locks the entire row.<br />
437