Phần 3: Lập trình Cơ sở dữ liệu nâng cao với ADO.NET_Chương 14 - Pdf 72

Phần 3: Lập trình Cơ sở dữ liệu nâng cao với ADO.NET

DANH SÁCH CÁC CHƯƠNG

Chương 14: Điều khiển Giao dịch nâng cao
Chương 15: Giới thiệu những ứng dụng Web -ASP.NET
Chương 16: Sử dụng hỗ trợ XML của SQL Server
Chương 17: Những dịch vụ Mạng Chương 14: Điều khiển Giao dịch nâng cao

Tổng quan

Trong Chương 3
, "Giới thiệu về ngôn ngữ truy vấn có cấu trúc, " Bạn đã thấy là bạn có thể nhóm những câu lệnh
SQL vào trong những giao dịch như thế nào. Những câu lệnh SQL này được coi như một đơn vị công việc lôgíc.
Một ví dụ của điều này là một chuyển đổi tiền từ tài khoản này sang tài khoản khác sử dụng hai phát biểu
UPDATE. Một rút tiền ra khỏi một tài khoản, và một chuyển tiền vào trong mộ
t tài khoản khác . Cả hai phát
biểu UPDATE có thể được xem như là một giao dịch đơn vì cả hai phát biểu đều phải được giao phó hay phục
nguyên cùng nhau, nếu không tiền có thể bị mất.
Những cơ sở dữ liệu hiện đại có thể xử lý nhiều người sử dụng và những chương trình truy cập cơ sở dữ liệu
đồng thời, mỗi chương trình chạy tiềm tàng những giao dịch của mình trong cơ sở dữ liệu. Điều này được biết
như những giao dịch trùng hợp bởi vì họ được chạy cùng lúc. Phần mềm cơ sở dữ liệu phải có khả năng để thỏa
mãn những nhu cầu của tất cả những giao dịch trùng hợp này, cũng như bảo trì sự toàn vẹn của những hàng được
cất giữ trong những bảng cơ sở dữ liệu. Bạn có thể kiểm soát lượng cô lập tồn tại giữa những giao dịch của bạn
và những giao dịch khác mà có lẽ đang được chạy trong cơ sở dữ liệu.
Trong Chương 8, "Thực hiện những lệnh Cơ sở dữ liệu, " Bạn đã thấy cách sử dụng một giao dịch với một đối
tượng Lệnh như thế nào. Trong Chương 11, "Sử dụng những đối tượng Dataset để sửa đổi Dữ liệu, " Bạn đã thấy
cách sử dụng một giao dịch với một DataAdapter như thế nào. Trong chương này, bạn sẽ đi sâu vào điều khiển

trả về
Mô tả
Commit() void Thực hiện một giao phó để duy trì mẫu tin những câu lệnh SQL trong giao dịch.
Rollback() void Bị quá tải. Thực hiện một sự hồi nguyên để huỷ bỏ những câu lệnh SQL trong giao dịch.
Save() void Tạo ra một savepoint trong giao dịch mà có thể được dùng để huỷ bỏ một phần của giao
dịch này. Chuỗi được chuyển cho phương pháp này chỉ rõ tên savepoint. Và rồi bạn có thể
hồi nguyên giao dịch tới savepoint này ( xem " Sự thiết đặt một Savepoint ").

THIẾT ĐẶT MỘT
SavepointBạn có thể đặt một savepoint bất cứ nơi đâu bên trong một giao dịch. Điều này cho phép bạn hồi nguyên bất kỳ
sự thay đổi nào được làm tới những hàng trong cơ sở dữ liệu sau lúc thiết đặt savepoint của bạn.Điều này có lẽ
hữu ích nếu bạn có một giao dịch rất dài, bởi vì nếu bạn tạo ra một lỗi sau khi bạn thiết đặt một savepoint, Bạn
không cần phải hồi nguyên suốt quá trình giao dịch tới khởi đầu.

THIẾT ĐẶT MỘT
Saverpoint
SỬ DỤNG T-SQL

Bạn đặt một savepoint trong T-SQL sử dụng phát biểu SAVE TRANSACTION (Giao dịch Lưu trữ), hay phiên
bản tốc ký : SAVE TRANS. Cú pháp cho sự phát biểu này như sau:

SAVE TRANS[ACTION] { savepointName | @savepointVariable }

VỚI:

savepointName chỉ rõ một chuỗi chứa tên bạn muốn gán tới savepoint của bạn.


/*
Savepoint.sql illustrates how to use a savepoint
*/

USE Northwind

- step 1: begin the transaction
BEGIN TRANSACTION

- step 2: insert a row into the Customers table
INSERT INTO Customers (
CustomerID, CompanyName
) VALUES (
'J8COM', 'J8 Company'
)

- step 3: set a savepoint
SAVE TRANSACTION SaveCustomer
- step 4: insert a row into the Orders table
INSERT INTO Orders (
CustomerID
) VALUES (
'J8COM'
);

- step 5: rollback to the savepoint set in step 3
ROLLBACK TRANSACTION SaveCustomer

- step 6: commit the transaction
COMMIT TRANSACTION


mySqlTransaction.Save("SaveCustomer");

Và rồi Bạn có thể hồi nguyên bất kỳ sự thay đổi kế tiếp nào được thực hiện tới những hàng trong cơ sở dữ liệu
bởi việc gọi phương thức Rollback() của mySqlTransaction, với việc chuyển tên savepoint tới phương thức
Rollback(). Chẳng hạn:

mySqlTransaction.Rollback("SaveCustomer");

Chúng ta hãy quan sát một chương trình C# đầy đủ ,nó đặt một savepoint bên trong một giao dịch. Danh sách

14.2 cho thấy một chương trình thực hiện những bước sau đây:
1. Tạo ra một đối tượng SqlTransaction có tên mySqlTransaction.
2. Tạo ra một SqlCommand và gán thuộc tính Transaction (Giao dịch) của nó tới mySqlTransaction.
3. Chèn một hàng vào trong bảng Customers.
4. thiết đặt một savepoint bởi việc gọi phương thức Save() của mySqlTransaction, chuyển tên
SaveCustomer tới phương thức Save() .
5. Chèn một hàng vào trong bảng Orders.
6. Thực hiện một hồi nguyên tới savepoint được thiết lập trong bước 4, nó huỷ bỏ sự chèn thực hiện trong
bước 5 trước đây, nhưng vẫn duy trì sự chèn thực hiện trong bước 3.
7. Hi
ển thị hàng mới được thêm vào bảng Customers.
8. Xóa hàng mới từ bảng Customers
9. Giao phó giao dịch.

Danh sách 14.2: SAVEPOINT.CS

/*
Savepoint.cs illustrates how to set a savepoint in a transaction
*/

") VALUES ( " +
" 'J8COM', 'J8 Company' "+
")";
int numberOfRows = mySqlCommand.ExecuteNonQuery();
Console.WriteLine("Number of rows inserted = "+ numberOfRows);

// step 4: set a savepoint by calling the Save() method of
// mySqlTransaction, passing the name "SaveCustomer" to
// the Save() method
mySqlTransaction.Save("SaveCustomer");

// step 5: insert a row into the Orders table
Console.WriteLine("Inserting a row into the Orders table "+
"with a CustomerID of J8COM");
mySqlCommand.CommandText =
"INSERT INTO Orders ( " +
" CustomerID " +
") VALUES ( " +
"'J8COM' "+
")";
numberOfRows = mySqlCommand.ExecuteNonQuery();
Console.WriteLine("Number of rows inserted = "+ numberOfRows);

// step 6: rollback to the savepoint set in step 4
Console.WriteLine("Performing a rollback to the savepoint");
mySqlTransaction.Rollback("SaveCustomer");

// step 7: display the new row added to the Customers table
mySqlCommand.CommandText =
"SELECT CustomerID, CompanyName "+

Inserting a row into the Orders table with a CustomerID of J8COM
Number of rows inserted = 1
Performing a rollback to the savepoint
mySqlDataReader["CustomerID"] = J8COM
mySqlDataReader["CompanyName"] = J8 Company
Deleting row with CustomerID of J8COM
Number of rows deleted = 1
Committing the transaction

Thiết đặt mức cô lập Giao dịchMức cô lập giao dịch là hạn độ mà tới đó những sự thay đổi do một giao dịch tạo ra , được phân chia từ những
giao dịch trùng hợp khác. Trước khi Tôi đi vào những chi tiết của nhiều mức cô lập giao dịch, bạn cần hiểu
những kiểu sự cố mà có lẽ sẽ xuất hiện khi những giao dịch thường kỳ thử truy nhập vào cùng những hàng trong
một bảng. Trong danh sách sau đây, Tôi sẽ sử dụng những ví dụ của hai giao dịch trùng hợp mà đang truy cập
vào cùng những hàng để minh họa ba kiểu sự cố về xử lý giao dịch tiềm tàng.

Phantoms(ma thuật): Transaction1 đọc một tập hợp của những hàng trả về bởi một mệnh đề WHERE được
chỉ rõ. rồi Transaction 2 chèn vào một hàng mới, mà cũng xảy ra để đáp ứng mệnh đề WHERE của truy vấn
sử dụng trước đó bởi Transaction 1. rồi Transaction1 đọc những hàng lần nữa sử dụng truy vấn giống như
vậy, nhưng bây giờ lại thấy hàng vừa được chèn vào bởi Transaction 2. Hàng mới này được biết như một "
ma thuật", bởi vì đối với Transaction 1, hàng này có vẻ như xuất hiện cách ma thuật.

Nonrepeatable reads: Transaction1 đọc một hàng, và Transaction 2 cập nhật cùng hàng vừa được đọc bởi
Transaction 1. Rồi Transaction 1 lại đọc cũng hàng đó lần nữa và phát hiện rằng hàng nó đọc trước đó bây
giờ đã thay đổi. Điều này được biết như một " sự đọc không thể lặp lại ", bởi vì hàng trước đấy đọc bởi
Transaction 1 đã được thay đổi.

Dirty Reads (Sự đọc dơ): Transaction 1 cập nhật một hàng nhưng không giao phó sự cập nhật. Transaction

giao dịch khác truy cập những hàng này . Bạn sử dụng SERIALIZABLE (xếp theo thứ
tự) chỉ khi bạn
phải bảo đảm rằng giao dịch của bạn được cô lập từ những giao dịch khác. Bạn sẽ học nhiều hơn về
điều này sau trong mục " Tìm hiểu những sự khóa SQL Server."

Ngoài ra, ADO.NET còn hỗ trợ một số mức cô lập giao dịch, được định nghĩa trong liệt kê
System.Data.IsolationLevel. Bảng 14.4 cho thấy những thành viên của liệt kê này.

Bảng 14.4: những thành viên liệt kê IsolationLevel

Mức cô lập Mô tả
Chaos
Những sự thay đổi đang xem xét từ nhiều giao dịch được cô lập không thể bị ghi đè lên. SQL
Server không hỗ trợ mức cô lập này.
ReadCommitted
Những" ma thuật" và "sự đọc không đáng được lặp lại " được cho phép, nhưng những sự
đọc bẩn thỉu thì không. Đây là mặc định.
ReadUncommitted
Ma thuật, những sự đọc không đáng được lặp lại, và những sự đọc dơ được cho phép.
RepeatableRead
Ma thuật được cho phép, nhưng những sự đọc bẩn và không đáng được lặp lại thì không .
Serializable
Ma thuật, những sự đọc không đáng được lặp lại, và những sự đọc bẩn không được cho phép.
Unspecified
Một mức cô lập khác so với cái chỉ định hiện đang dùng, nhưng mức độ không thể xác định
được . SQL Server không hỗ trợ mức cô lập này. Thiết đặt giao dịch sử dụng T- SQL



Chúng ta hãy quan sát một ví dụ đầy đủ mà thiết đặt mức cô lập giao dịch sử dụng T- SQL. Danh sách 14.3 cho
thấy một ví dụ sử dụng Script T- SQL để đặt mức cô lập giao dịch đầu tiên tới SERIALIZABLE (xếp theo thứ tự)
và thực hiện một giao dịch, và sau đó thiết đặt mức tới READ COMMITTED và thực hiện giao dịch khác.

Danh sách 14.3: TransactionIsolation.sql

/*
TransactionIsolation.sql illustrates how to set the
transaction isolation level
*/

USE Northwind

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION
SELECT CustomerID, CompanyName
FROM Customers
WHERE CustomerID IN ('ALFKI', 'J8COM')

INSERT INTO Customers (
CustomerID, CompanyName
) VALUES (
'J8COM', 'J8 Company'
)
UPDATE Customers
SET CompanyName = 'Widgets Inc.'
WHERE CustomerID = 'ALFKI'



Cùng với việc đặt mức cô lập giao dịch của một đối tượng SqlTransaction, bạn sẽ thấy một ví dụ cho thấy hiệu
ứng của những mức khác nhau được thiết đặt ở một chương trình C# .

Bạn tạo ra một đối tượng SqlTransaction bởi sự gọi phương thức BeginTransaction() của đối tượng
SqlConnection. Phương thức này bị quá tải như sau:

SqlTransaction BeginTransaction()
SqlTransaction BeginTransaction(IsolationLevel myIsolationLevel)
SqlTransaction BeginTransaction(string transactionName
)
SqlTransaction BeginTransaction(IsolationLevel myIsolationLevel, string
transactionName)

VỚI:
myIsolationLevel: chỉ rõ mức cô lập giao dịch của bạn. Đây là một hằng số từ liệt kê
System.Data.IsolationLevel , cho những thành viên được chỉ định trước đó trong Bảng 14.4.

transactionName chỉ rõ một chuỗi chứa tên bạn muốn gán tới giao dịch của các bạn.

Trong những ví dụ trong mục này, giả thiết bạn có một SqlConnection mở có tên mySqlConnection mà được nối
tới cơ sở dữ liệu Northwind SQL server. Ví dụ sau đây tạ
o ra một SqlTransaction có tên serializableTrans bởi sự
gọi phương thức BeginTransaction() của mySqlConnection; chú ý IsolationLevel của Serializable được chuyển
cho BeginTransaction():

SqlTransaction serializableTrans =
mySqlConnection.BeginTransaction(IsolationLevel.Serializable);

Ví dụ kế tiếp tạo ra một SqlCommand có tên serializableCommand, và đặt thuộc tính Transaction của nó tới

Danh sách 14.4 cho thấy một chương trình chứa những phương thức sau đây:

DisplayRows() chọn và hiển thị bất kỳ hàng nào từ bảng Customers với một CustomerID là ALFKI hay
J8COM.

PerformSerializableTransaction() Thực hiện mã được trình bày trước đó trong mục này để tạo ra một đối
tượng SqlTransaction với một mức cô lập là Serializable, và sử dụng nó để thực hiện một phát biểu INSERT
và UPDATE.

PerformReadCommittedTransaction() Tạo ra một đối tượng SqlTransaction với một mức cô lập là
ReadCommitted, Và sử dụng nó để thực hiện những phát biểu Cập nhật và Xóa.

Danh sách 14.4: TransactionIsolation.cs

/*
TransactionIsolation.cs illustrates how to set the
transaction isolation level
*/

using System;
using System.Data;
using System.Data.SqlClient;

class TransactionIsolation
{
public static void DisplayRows(
SqlCommand mySqlCommand
)
{
mySqlCommand.CommandText =

serializableCommand.Transaction = serializableTrans;

// call the DisplayRows() method to display rows from
// the Customers table
DisplayRows(serializableCommand);

// insert a new row into the Customers table
Console.WriteLine("Inserting new row into Customers table "+
"with CustomerID of J8COM");
serializableCommand.CommandText =
"INSERT INTO Customers ("+
"CustomerID, CompanyName "+
") VALUES ("+
"'J8COM', 'J8 Company' "+
")";
int numberOfRows = serializableCommand.ExecuteNonQuery();
Console.WriteLine("Number of rows inserted = "+ numberOfRows);

// update a row in the Customers table
Console.WriteLine("Setting CompanyName to 'Widgets Inc.' for "+
"row with CustomerID of ALFKI");
serializableCommand.CommandText =
"UPDATE Customers "+
"SET CompanyName = 'Widgets Inc.' "+
"WHERE CustomerID = 'ALFKI'";
numberOfRows = serializableCommand.ExecuteNonQuery();
Console.WriteLine("Number of rows updated = "+ numberOfRows);
DisplayRows(serializableCommand);
// commit the transaction
serializableTrans.Commit();


// delete the new row from the Customers table
Console.WriteLine("Deleting row with CustomerID of J8COM");
readCommittedCommand.CommandText =
"DELETE FROM Customers "+
"WHERE CustomerID = 'J8COM'";
numberOfRows = readCommittedCommand.ExecuteNonQuery();
Console.WriteLine("Number of rows deleted = "+ numberOfRows);

DisplayRows(readCommittedCommand);

// commit the transaction
readCommittedTrans.Commit();
}
public static void Main()
{
SqlConnection mySqlConnection =
new SqlConnection(
"server=localhost;database=Northwind;uid=sa;pwd=sa"
);
mySqlConnection.Open();
PerformSerializableTransaction(mySqlConnection);
PerformReadCommittedTransaction(mySqlConnection);
mySqlConnection.Close();
}
}
Đầu ra từ chương trình này như sau:
In PerformSerializableTransaction()
mySqlDataReader["CustomerID"] = ALFKI
mySqlDataReader["CompanyName"] = Alfreds Futterkiste

bị khóa. Chẳng hạn, một sự khóa hàng có một độ hạt tinh luyện hơn so với một sự khóa trang.

Bảng 14.5: những kiểu khóa của máy chủ phục vụ SQL

Kiểu khóa Mô tả
Row (RID) Được đặt lên một hàng trong một bảng. Thay thế cho định danh hàng. Thường dùng để xác định
một hàng duy nhất.
Key (KEY) Được đặt lên một hàng bên trong một chỉ số. Dùng để bảo vệ những phạm vi của khóa trong
serializable transactions.
Page (PAG) Được đặt trên một trang, có chứa 8 KB hàng hay chỉ số dữ liệu.
Extent
(EXT)
Được đặt trên một phạm vi, một nhóm kề nhau của 8 Dữ liệu hay những trang chỉ số
Table (TAB) Đặt trên một bảng và khóa tất cả những hàng và những chỉ số trong bảng này.
Database
(DB)
Dùng để khóa toàn bộ cơ sở dữ liệu khi người quản trị cơ sở dữ liệu đặt nó vào trong kiểu người
sử dụng đơn cho sự bảo trì. Những kiểu khóa của máy chủ phục vụ SQL
Máy chủ phục vụ SQL sử dụng những kiểu khóa khác nhau để xác định mức khóa đặt trên nguồn tài nguyên.
Những kiểu khóa này được trình bày trong Bảng 14.6. Bạn sẽ thấy những kiểu khóa này trong mục kế tiếp.

Bảng 14.6: những kiểu khóa của máy chủ phục vụ SQL

Kiểu khóa Mô tả
Shared (S) Chỉ định một giao dịch sẽ đọc từ nguồn tài nguyên sử dụng một phát biểu SELECT. Ngăn
ngừa những giao dịch khác sửa đổi nguồn tài nguyên được khóa. Một sự khóa dùng chung
được thả tự do ngay khi dữ liệu được đọc- trừ phi mức cô lập giao dịch được đặt tới

giao dịch nào khác có thể đặt một sự khóa trên một tài nguyên mà đã có một khóa Sch- M
trên nó.
Schema stability
(Sch-S)
Chỉ báo rằng một câu lệnh SQL mà sử dụng nguồn tài nguyên, sắp sửa được thực hiện, như
một phát biểu SELECT chẳng hạn. Những giao dịch khác có thể đặt một khóa trên một tài
nguyên mà đã có một khóa Sch- S trên nó; chỉ một sự khóa cải biến mô hình bị ngăn cản.
Bulk update (BU) Chỉ báo rằng một thao tác sao chép khối lượng lớn để tải những hàng vào trong một bảng sẽ
được thực hiện. Một khóa cập nhật khối lượng lớn cho phép những quá trình khác tới khối dữ
liệu _sao chép dữ liệu đồng thời vào trong cùng một bảng , nhưng cản trở những quá trình
khác mà không phải là dữ liệu sao chép khối lớn truy nhập vào bảng. Để thêm thông tin về dữ
liệu sao chép khối lớn tới một bảng, xem những sách tài liệu trực tuyến Máy chủ phục vụ
SQL.

Xem thông tin về khóa máy chủ phục vụ SQL

Bạn có thể xem thông tin về khóa trong một cơ sở dữ liệu sử dụng SQL Server Enterprise Manager. Bạn mở thư
mục Management, mở nút Current Activity (hoạt động hiện thời), rồi mở nút Locks/Process ID hoặc những nút
Locks/Object . nút Locks/Process ID cho bạn thấy những khóa được đặt bởi mỗi Quá trình; mỗi quá trình có một
số SPID mà được gán bởi SQL Server để xác định quá trình. nút Locks/Object cho bạn thấy những khóa được
đặt trên mỗi nguồn tài nguyên bởi tất cả các quá trình.

Mẹo nhỏ: Bạn cũng có thể cũng xem thông tin về khóa bởi việc thực thi thủ tục lưu trữ sp_lock , mặc dù
Enterprise Manager tổ chức thông tin trong một định dạng dễ đọc hơn.
Giả thiết bạn đã bắt đầu giao dịch sau (thí dụ, sử dụng Query Analyzer) với những câu lệnh T - SQL sau đây:

USE Northwind
BEGIN TRANSACTION
UPDATE Customers
SET CompanyName = 'Widgets Inc.'

Owner kiểu khóa chủ sở hữu, như Sess (khóa phiên ) hay Xact (khóa giao dịch).

Index tên của chỉ số sẽ được khóa (nếu có).

Resource từ định danh tài nguyên của đối tượng sẽ bị khóa (nếu có).

Khóa Giao dịch

Một giao dịch có thể ngăn giao dịch khác thu một khóa trên một tài nguyên. Chẳng hạn, chúng ta hãy cho là bạn
bắt đầu một giao dịch sử dụng T -SQL sau, nó đồng nhất với T- SQL trong mục trước :

USE Northwind
BEGIN TRANSACTION
UPDATE Customers
SET CompanyName = 'Widgets Inc.'
WHERE CustomerID = 'ALFKI'

Như bạn thấy trong mục trước đây, nó đặt một số khóa trên những đối tượng Customers.

Nếu bạn thử cập nhật cùng một hàng - mà không kết thúc giao dịch trước - sử dụng những câu lệnh T-SQL sau
đây:

USE Northwind
UPDATE Customers
SET CompanyName = 'Alfreds Futterkiste'
WHERE CustomerID = 'ALFKI'

rồi Cập nhật này sẽ đợi cho đến khi giao dịch trước hòan tất việc giao phó hay hồi nguyên. Hình 14.4 cho thấy
rằng hai giao dịch này được bắt đầu trong Query Analyzer. Giao dịch đầu tiên, được trình bày trong phần trên
của Hình 14.4 , đang khóa giao dịch thứ hai trong phần dưới.

Blocking và Serializable/Repeatable Read Transactions
Serializable và repeatable read transactions khóa những hàng mà chúng đang truy xuất, như thế những giao dịch
khác không thể cập nhật những hàng đó. Serializable và repeatable read transactions làm điều này để những hàng
không bị thay đổi sau khi chúng đọc.

Ví dụ, nếu bạn chọn hàng từ bảng Customers với một CustomerID là ALFKI sử dụng một serializable
transaction, rồi nỗ lực cập nhật hàng này sử dụng Transaction thứ hai, thì Transaction thứ hai sẽ bị khóa. Nó bị
khóa vì serializable transaction khóa hàng được truy xuất và Transaction thứ hai không thể lấ
y một khóa trên
hàng này.

Danh sách 14.5 cho thấy một ví dụ về điều này. Transaction thứ hai gán khóa timeout tới 1 giây. Có nghĩa là
chương trình sẽ ném ra một SqlException đơn giản hơn là treo máy khi Transaction thứ hai không thể làm chủ
một khóa trên hàng ALFKI trong bảng Customers .

Danh sách 14.5: Block.c

/*
Block.cs illustrates how a serializable command locks
the rows it retrieves so that a second transaction
cannot get a lock to update one of these retrieved rows
that has already been locked
*/

using System;
using System.Data;
using System.Data.SqlClient;

class Block
{

serConnection.Open();
rcConnection.Open();

// create the first SqlTransaction object and start the transaction
// by calling the BeginTransaction() method of the SqlConnection
// object, passing the IsolationLevel of Serializable to the method
SqlTransaction serializableTrans =

serConnection.BeginTransaction(IsolationLevel.Serializable);

// create a SqlCommand and set its Transaction property
// to serializableTrans
SqlCommand serializableCommand =
serConnection.CreateCommand();
serializableCommand.Transaction = serializableTrans;

// call the DisplayRows() method to display rows from
// the Customers table;
// this causes the rows to be locked, if you comment
// out the following line then the INSERT and UPDATE
// performed later by the second transaction will succeed
DisplayRows(serializableCommand); // *

// create the second SqlTransaction object
SqlTransaction readCommittedTrans =
rcConnection.BeginTransaction(IsolationLevel.ReadCommitted);

// create a SqlCommand and set its Transaction property
// to readCommittedTrans
SqlCommand readCommittedCommand =


// display the new rows and rollback the changes
DisplayRows(readCommittedCommand);
Console.WriteLine("Rolling back changes");
readCommittedTrans.Rollback();
}
catch (SqlException e)
{
Console.WriteLine(e);
}
finally
{
serConnection.Close();
rcConnection.Close();
}
}
}

Cảnh báo: Nếu bạn biên dịch và chạy chương trình này như nó có, thì nó sẽ ném một SqlException. Đây là sự
ước định trước, như nó cho bạn thấy sự nỗ lực để lấy một khóa time out. Nếu bạn chuyển lệnh gọi đầu tiên tới
phương thức DisplayRows() thành một ghi chú trong chương trình này [ Đánh dấu với một dấu sao (*)], thì
chương trình sẽ không ném ra một SqlException. Vì đây là ghi chú (lệnh gọi đầu tiên tới DisplayRows() )nó tách
serializable transaction khỏi việc truy xuất và do đó khóa những hàng. và Transaction thứ hai có thể lấy khóa
trên hàng ALFKI.
Đầu ra từ chương trình này như sau (chú ý nó ném ra một SqlException khi vượt quá thời gian timeout của
khóa ):

mySqlDataReader["CustomerID"] = ALFKI
mySqlDataReader["CompanyName"] = Alfreds Futterkiste
Inserting new row into Customers table with CustomerID of J8COM

BEGIN TRANSACTION
UPDATE Products
SET ProductName = ' Chai'
WHERE ProductID = 1
UPDATE Customers
SET CompanyName = ' Alfreds Futterkiste'
WHERE CustomerID = 'ALFKI'
COMMIT TRANSACTIONChú ý: cả T1 lẫn T2 đều cập nhật cùng những hàng như nhau trong bảng Customers và Products. Nếu T1 và T2
được thực thi kế tiếp nhau vào những thời gian khác nhau, T1 được thực hiện rồi hoàn thành, theo sau là T2, thì
không có sự cố gì. Tuy nhiên, nếu T1 và T2 được thực hiện cùng lúc với những sự phát biểu Cập nhật của chúng ,
thì một sự bế tắc xuất hiện. Hãy xem xét một ví dụ về điều này, sử dụng những bước sau đây:

1. T1 bắt đầu.
2. T2 bắt đầu.
3. T1 khóa hàng Customers và cập nhật hàng.
4. T2 khóa hàng Products và cập nhật hàng.
5. T2 đợi khóa trên hàng Products, mà hiện thời được giữ bởi T1.
6. T1 đợi khóa trên hàng Customers, mà hiện thời được giữ bởi T2.

Trong bước 5, T2 đợi một khóa giữ bởi T1. Trong bước 6, T1 đợi một khóa giữ bởi T2. Như vậy, một sự bế tắc
xuất hiện khi cả hai giao dịch đang đợi lẫn nhau. Cả hai giao dịch giữ qua lại những khóa yêu cầu. Máy chủ phục
vụ SQL sẽ phát hiện ra bế tắc và hồi nguyên một trong số những giao dịch. Máy chủ phục vụ SQL hồi nguyên
những giao dịch rẻ nhất để huỷ, và cũng trả về một lỗi cho biết một bế tắc xuất hiện.
Bạn cũng có thể chọn giao dịch mà sẽ được hồi nguyên sử dụng lệnh T- SQL SET DEADLOCK_ PRIORITY,
nó sử dụng cú pháp sau đây:

SET DEADLOCK_PRIORITY { LOW | NORMAL | @variable }

*/

using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;

class Deadlock
{
// create two SqlConnection objects
public static SqlConnection t1Connection =
new SqlConnection(
"server=localhost;database=Northwind;uid=sa;pwd=sa"
);
public static SqlConnection t2Connection =
new SqlConnection(
"server=localhost;database=Northwind;uid=sa;pwd=sa"
);
// declare two SqlTransaction objects
public static SqlTransaction t1Trans;
public static SqlTransaction t2Trans;

// declare two SqlCommand objects
public static SqlCommand t1Command;
public static SqlCommand t2Command;

public static void UpdateCustomerT1()
{
// update the row with a CustomerID of ALFKI
// in the Customers table using t1Command

t1Command.CommandText =
"UPDATE Products "+
"SET ProductName = 'Chai' "+
"WHERE ProductID = 1";
int numberOfRows = t1Command.ExecuteNonQuery();
Console.WriteLine("Number of rows updated = "+ numberOfRows);
}

public static void UpdateCustomerT2()
{
// update the row with a CustomerID of ALFKI
// in the Customers table using t2Command
Console.WriteLine("Setting CompanyName to 'Alfreds Futterkiste' "+
"for row with CustomerID of ALFKI using t2Command");
t2Command.CommandText =
"UPDATE Customers "+
"SET CompanyName = 'Alfreds Futterkiste' "+
"WHERE CustomerID = 'ALFKI'";
int numberOfRows = t2Command.ExecuteNonQuery();
Console.WriteLine("Number of rows updated = "+ numberOfRows);
}

public static void Main()
{
// open the first connection, begin the first transaction,
// and set the lock timeout to 5 seconds
t1Connection.Open();
t1Trans = t1Connection.BeginTransaction();
t1Command = t1Connection.CreateCommand();
t1Command.Transaction = t1Trans;


Ghi chú:
Bạn có thể nghĩ về một luồng như một quá trình riêng biệt trong chương trình của bạn, và mỗi luồng xuất
hiện để thực hiện trong đường song song với những luồng khác.Về một thảo luận chi tiết của những luồng,
xem cuốn sách "Mastering Visual C# .NET" do Jason Price và Mike Gunderloy ( Sybex, 2002).

Chương trình trình bày trong Danh sách 14.6 chứa những phương thức sau đây:

UpdateCustomerT1() Cập nhật hàng với một CustomerID là ALFKI trong bảng Customers sử dụng giao
dịch đầu tiên. Đặc biệt, nó đặt CompanyName tới Widgets Inc.
UpdateProductT2() Cập nhật hàng với một ProductID là 1 trong bảng Products sử dụng giao dịch thứ
hai. Đặc biệt, nó đặt ProductName tới Widget.
UpdateProductT1() Cập nhật hàng với ProductID là 1 trong bảng Products sử dụng sự giao dịch đầu
tiên. Đặc biệt, nó đặt ProductName tới Chai.
UpdateCustomerT2() Cập nhật hàng với một CustomerID là ALFKI trong bảng Customers sử dụng
giao dịch thứ hai. Đặc biệt nó đặt CompanyName tới Alfreds Futterkiste.
Những phương thức này sẽ được gọi bởi những luồng để thực hiện cập nhật được đặt xen kẽ.
Ghi chú
Chương trình này chỉ báo giao dịch thứ hai sẽ được hồi nguyên khi sự bế tắc xuất hiện sử dụng lệnh SET
DEADLOCK_PRIORITY LOW.
Đầu ra của chương trình này như sau:
Setting CompanyName to 'Widgets Inc.' for row
with CustomerID of ALFKI using t1Command
Number of rows updated = 1
Setting ProductName to 'Widget' for the row
with ProductID of 1 using t2Command
Number of rows updated = 1
Setting ProductName to 'Chai' for the row

Trích đoạn Sử dụng kiểu RAW Sử dụng tùy chọn BASE64 Nhị phân Những biểu thức XPath Giới thiệu XSLT Chạy những phát biểu SELECT
Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status