Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

Beginning Microsoft SQL Server 2008 ... - S3 Tech Training Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

cdn.s3techtraining.com
from cdn.s3techtraining.com More from this publisher
17.06.2013 Views

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

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!