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

Chia sẻ: Trần Tiến đạt | Ngày: | Loại File: PDF | Số trang:124

0
339
lượt xem
229
download

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

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

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...

Chủ đề:
Lưu

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

  1. 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 giao dịch nâng cao sử dụng SQL Server và ADO.NET. Những mặt nổi bật trong Chương này: . Lớp SqlTransaction . Những thuộc tính giao dịch ACID . Sự Thiết đặt một savepoint . Đặt mức cô lập giao dịch . Hiểu về những khóa SQL Server LỚP SqlTransaction: Có ba lớp Giao dịch SqlTransaction, OleDbTransaction, và OdbcTransaction. Bạn sử dụng một đối tượng Transaction để đại diện cho một giao dịch cơ sở dữ liệu, và một đối tượng của lớp SqlTransaction để đại diện cho một giao dịch cơ sở dữ liệu trong một cơ sở dữ liệu SQL Server. Bảng 14.1 trình bày một số thuộc tính SqlTransaction, và Bảng 14.2 cho thấy một số những phương thức của SqlTransaction. Bạn sẽ xem xét cách sử dụng một số thuộc tính và phương pháp trong chương này. Bảng 14.1: những thuộc tính SqlTransaction
  2. Thuộc tính Kiểu dữ liệu Mô tả Connection SqlConnection Lấy kết nối cho giao dịch. IsolationLevel IsolationLevel Lấy mức cô lập cho giao dịch ( xem " thiết đặt mức cô lập Giao dịch") Bảng 14.2: Những phương pháp SqlTransactiontransaction. Phương Kiểu Mô tả thức trả về 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 Savepoint Bạ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. savepointVariable chỉ rõ một biến T- SQL chứa tên savepoint của bạn. Biến của bạn phải thuộc về kiểu dữ liệu char, varchar, nchar, hay nvarchar. Ví dụ sau đây thiết đặt một savepoint có tên SaveCustomer: SAVE TRANSACTION SaveCustomer Chúng ta hãy quan sát một script ví dụ T - SQL đầy đủ , nó đặt một savepoint bên trong một giao dịch. Danh sách 14.1 cho thấy một script T- SQL thực hiện những bước sau đây: 1. Bắt đầu một giao dịch. 2. Chèn một hàng vào trong bảng Customers với một CustomerID là J8COM. 3. thiết đặt một savepoint . 4. Chèn một hàng vào trong bảng Orders với một CustomerID là J8COM. 5. Thực hiện một hồi nguyên tới savepoint, nó huỷ bỏ sự chèn thực hiện trong bước 4 trước đây, nhưng vẫn duy trì sự chèn thực hiện trong bước 2. 6. Giao phó giao dịch, nó giao phó hàng được chèn vào trong bảng Customers trong bước 2.
  3. 7. Lựa chọn hàng mới từ bảng Customers. 8. Thử chọn hàng mà đã được hồi nguyên trong bước 5 từ bảng Customers. 9. Xóa hàng mới từ bảng Customers. Danh sách 14.1: SAVEPOINT.SQL /* 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 - step 7: select the new row from the Customers table SELECT CustomerID, CompanyName FROM Customers WHERE CustomerID = 'J8COM' - step 8: attempt to select the row from the Orders table - that was rolled back in step 5 SELECT OrderID, CustomerID FROM Orders WHERE CustomerID = 'J8COM' - step 9: delete the new row from the Customers table DELETE FROM Customers WHERE CustomerID = 'J8COM' Để chạy Script “ Savepoint.sql” sử dụng bộ phân tích truy vấn (Query Analyzer), bạn chọn File – Open , Mở script từ thư mục sql, và nhấn F5 trên bàn phím hay chọn Query – Execute từ thực đơn (menu). Hình 14.1 trình
  4. bày script “Savepoint.sql” đang chạy trong bộ phân tích truy vấn (Query Analyzer) Hình 14.1: chạy script “Savepoint.sql “ trong Query Analyzer Thiết đặt một Savepoint sử dụng một đối tượng SqlTransaction Bạn đặt một savepoint trong một đối tượng SqlTransaction bằng cách gọi phương thức Save() của nó, gởi một chuỗi chứa tên mà bạn muốn gán cho savepoint của bạn. Giả thiết bạn có một đối tượng SqlTransaction có tên mySqlTransaction; Ví dụ sau đây những thiết đặt một SaveCustomer có tên saveCustomer bằng cách gọi phương thức Save() của mySqlTransaction: 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
  5. /* Savepoint.cs illustrates how to set a savepoint in a transaction */ using System; using System.Data; using System.Data.SqlClient; class Savepoint { public static void Main() { SqlConnection mySqlConnection = new SqlConnection( "server=localhost;database=Northwind;uid=sa;pwd=sa" ); mySqlConnection.Open(); // step 1: create a SqlTransaction object SqlTransaction mySqlTransaction = mySqlConnection.BeginTransaction(); // step 2: create a SqlCommand and set its Transaction property // to mySqlTransaction SqlCommand mySqlCommand = mySqlConnection.CreateCommand(); mySqlCommand.Transaction = mySqlTransaction; // step 3: insert a row into the Customers table Console.WriteLine("Inserting a row into the Customers table "+ "with a CustomerID of J8COM"); mySqlCommand.CommandText = "INSERT INTO Customers ( " + " CustomerID, CompanyName " + ") 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);
  6. // 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 "+ "FROM Customers "+ "WHERE CustomerID = 'J8COM'"; SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader(); while (mySqlDataReader.Read()) { Console.WriteLine("mySqlDataReader[\" CustomerID\"] = "+ mySqlDataReader["CustomerID"]); Console.WriteLine("mySqlDataReader[\" CompanyName\"] = "+ mySqlDataReader["CompanyName"]); } mySqlDataReader.Close(); // step 8: delete the new row from the Customers table Console.WriteLine("Deleting row with CustomerID of J8COM"); mySqlCommand.CommandText = "DELETE FROM Customers "+ "WHERE CustomerID = 'J8COM'"; numberOfRows = mySqlCommand.ExecuteNonQuery(); Console.WriteLine("Number of rows deleted = "+ numberOfRows); // step 9: commit the transaction Console.WriteLine("Committing the transaction"); mySqlTransaction.Commit(); mySqlConnection.Close(); } } Đầu ra từ chương trình này sau: Inserting a row into the Customers table with a CustomerID of J8COM Number of rows inserted = 1 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ịch Mứ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
  7. 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 2 đọc hàng được cập nhật. Rồi Transaction 1 thực hiện một hồi nguyên, huỷ bỏ sự cập nhật trước đây. Bây giờ hàng vừa được đọc bởi Transaction 2 không còn hợp lệ nữa ( hay nó "dơ ") vì sự cập nhật thực hiện bởi Transaction 1 không được giao phó khi hàng được đọc bởi Transaction 2. Để giải quyết những vấn đề tiềm tàng này, những cơ sở dữ liệu thực hiện nhiều mức cô lập giao dịch để cản trở những giao dịch trùng hợp can thiệp lẫn nhau. SQL tiêu chuẩn định nghĩa bốn mức cô lập, được trình bày trong Bảng 14.3. Những mức này được trình bày theo mức cô lập tăng dần. Bảng 14.3: những mức cô lập Tiêu chuẩn SQL Mức cô lập Mô tả READ Ma thuật, những sự đọc không thể lặp lại, và những sự đọc dơ được cho phép. UNCOMMITTED READ COMMITTED Ma thuật và sự đọc không không thể lặp lại được cho phép, nhưng những sự đọc dơ thì Không. Đây là mặc định cho SQL Server. REPEATABLE READ Ma thuật được cho phép, nhưng những sự đọc dơ và không thể lập lại thì không. SERIALIZABLE Ma thuật, những sự đọc không không thể lặp lại, và những sự đọc dơ không được cho phép. Đây là mặc định cho SQL tiêu chuẩn. SQL Server hỗ trợ tất cả những mức cô lập giao dịch này. Mức cô lập giao dịch mặc định được định nghĩa bởi SQL tiêu chuẩn được xếp theo thứ tự, ngoại trừ mặc định sử dụng bởi SQL Server là READ COMMITTED (sự đọc được giao phó), nó được chấp nhận cho hầu hết những ứng dụng. Cảnh báo: khi bạn đặt mức cô lập giao dịch là SERIALIZABLE (xếp theo thứ tự), bất kỳ hàng nào bạn truy cập bên trong một giao dịch kế tiếp sẽ được " khóa ", có nghĩa rằng không có giao dịch nào khác có thể sửa đổi những hàng này. Thậm chí những hàng bạn truy xuất sử dụng một phát biểu SELECT cũng sẽ bị khóa. Bạn phải giao phó hay hồi nguyên giao dịch để bỏ những khóa và cho phép những 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.
  8. 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 Cũng như việc học thiết đặt mức cô lập giao dịch sử dụng T- SQL, Bạn sẽ thấy một ví dụ trình bày hiệu ứng của việc thiết đặt những mức cô lập giao dịch khác nhau trong SQL Server- sử dụng công cụ phân tích truy vấn (Query Analyzer tool). Để thiết đặt mức cô lập giao dịch trong T- SQL, Bạn sử dụng lệnh SET TRANSACTION ISOLATION LEVEL. Cú pháp cho lệnh này như sau: SET TRANSACTION ISOLATION LEVEL { READ COMMITTED | READ UNCOMMITTED | REPEATABLE READ | SERIALIZABLE } Như bạn có thể thấy từ cú pháp trước đây, bạn có thể đặt cô lập giao dịch tới bất kỳ những mức nào chỉ ra trước đó trong Bảng 14.3. Ví dụ sau đây đặt mức cô lập giao dịch tới SERIALIZABLE: SET TRANSACTION ISOLATION LEVEL SERIALIZABLE Ghi chú Mức cô lập giao dịch được gán cho phiên họp của các bạn. Bởi vậy, nếu bạn thực hiện nhiều giao dịch trong một phiên họp, tất cả những giao dịch của bạn sẽ sử dụng cùng mức như vậy. Nếu bạn muốn thay đổi mức trong phiên họp của bạn, bạn đơn giản thực hiện lệnh SET TRANSACTION ISOLATION LEVEL với mức mới của bạn. Tất cả các giao dịch kế tiếp trong phiên họp của bạn sẽ sử dụng mức mới. Ví dụ sau đây đặt mức cô lập giao dịch tới READ COMMITTED: SET TRANSACTION ISOLATION LEVEL READ COMMITTED 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 */
  9. 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' SELECT CustomerID, CompanyName FROM Customers WHERE CustomerID IN ('ALFKI', 'J8COM') COMMIT TRANSACTION SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRANSACTION UPDATE Customers SET CompanyName = 'Alfreds Futterkiste' WHERE CustomerID = 'ALFKI' DELETE FROM Customers WHERE CustomerID = 'J8COM' SELECT CustomerID, CompanyName FROM Customers WHERE CustomerID IN ('ALFKI', 'J8COM') COMMIT TRANSACTION Hình 14.2 Trình bày script TransactionIsolation.sql đang chạy trong Query Analyzer. Trong ô vuông những kết quả ở một nửa phần dưới của Query Analyzer, hai tập hợp đầu tiên của những hàng được sinh ra bởi transaction đầu tiên, và một hàng đơn cuối cùng được phát sinh bởi transaction thứ hai.
  10. Hình 14.2: Sript TransactionIsolation.sql đang chạy trong Query Analyzer. Đặt mức cô lập giao dịch của một đối tượng SqlTransaction 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 serializableTrans: SqlCommand serializableCommand = mySqlConnection.CreateCommand(); serializableCommand.Transaction = serializableTrans;
  11. Bất kỳ câu lệnh SQL nào được thực hiện sử dụng serializableCommand bây giờ sẽ sử dụng serializableTrans, và bởi vậy sẽ được thực hiện trong một serializable transaction. Ví dụ sau thực hiện một phát biểu INSERT để thêm một hàng vào bảng Customers : serializableCommand.CommandText = "INSERT INTO Customers ("+ "CustomerID, CompanyName "+ ") VALUES ("+ "'J8COM', 'J8 Company' "+ ")"; int numberOfRows = serializableCommand.ExecuteNonQuery(); Ví dụ kế tiếp thực hiện một phát biểu Cập nhật serializableCommand.CommandText = "UPDATE Customers "+ "SET CompanyName = 'Widgets Inc.' "+ "WHERE CustomerID = 'ALFKI'"; numberOfRows = serializableCommand.ExecuteNonQuery(); Cuối cùng, ví dụ sau đây giao phó những phát biểu UPDATE và INSERT bởi sự gọi phương thức Commit() của erializableTrans: serializableTrans.Commit(); 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 = "SELECT CustomerID, CompanyName "+ "FROM Customers "+
  12. "WHERE CustomerID IN ('ALFKI', 'J8COM')"; SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader(); while (mySqlDataReader.Read()) { Console.WriteLine("mySqlDataReader[\" CustomerID\"] = "+ mySqlDataReader["CustomerID"]); Console.WriteLine("mySqlDataReader[\" CompanyName\"] = "+ mySqlDataReader["CompanyName"]); } mySqlDataReader.Close(); } public static void PerformSerializableTransaction( SqlConnection mySqlConnection ) { Console.WriteLine("\nIn PerformSerializableTransaction()"); // create a 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 = mySqlConnection.BeginTransaction(IsolationLevel.Serializable); // create a SqlCommand and set its Transaction property // to serializableTrans SqlCommand serializableCommand = mySqlConnection.CreateCommand(); 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
  13. serializableTrans.Commit(); } public static void PerformReadCommittedTransaction( SqlConnection mySqlConnection ) { Console.WriteLine("\nIn PerformReadCommittedTransaction()"); // create a SqlTransaction object and start the transaction // by calling the BeginTransaction() method of the SqlConnection // object, passing the IsolationLevel of ReadCommitted to the method // (ReadCommitted is actually the default) SqlTransaction readCommittedTrans = mySqlConnection.BeginTransaction(IsolationLevel.ReadCommitted); // create a SqlCommand and set its Transaction property // to readCommittedTrans SqlCommand readCommittedCommand = mySqlConnection.CreateCommand(); readCommittedCommand.Transaction = readCommittedTrans; // update a row in the Customers table Console.WriteLine("Setting CompanyName to 'Alfreds Futterkiste' "+ "for row with CustomerID of ALFKI"); readCommittedCommand.CommandText = "UPDATE Customers "+ "SET CompanyName = 'Alfreds Futterkiste' "+ "WHERE CustomerID = 'ALFKI'"; int numberOfRows = readCommittedCommand.ExecuteNonQuery(); Console.WriteLine("Number of rows updated = "+ numberOfRows); // 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(); } }
  14. Đầu ra từ chương trình này như sau: In PerformSerializableTransaction() mySqlDataReader["CustomerID"] = ALFKI mySqlDataReader["CompanyName"] = Alfreds Futterkiste Inserting new row into Customers table with CustomerID of J8COM Number of rows inserted = 1 Setting CompanyName to 'Widgets Inc.' for row with CustomerID of ALFKI Number of rows updated = 1 mySqlDataReader["CustomerID"] = ALFKI mySqlDataReader["CompanyName"] = Widgets Inc. mySqlDataReader["CustomerID"] = J8COM mySqlDataReader["CompanyName"] = J8 Company In PerformReadCommittedTransaction() Setting CompanyName to 'Alfreds Futterkiste' for row with CustomerID of ALFKI Number of rows updated = 1 Deleting row with CustomerID of J8COM Number of rows deleted = 1 mySqlDataReader["CustomerID"] = ALFKI mySqlDataReader["CompanyName"] = Alfreds Futterkiste Tìm hiểu những sự khóa SQL server SQL Server sử dụng những sự khóa để thực hiện cô lập giao dịch và để bảo đảm thông tin được cất giữ chắc chắn trong một cơ sở dữ liệu .Những sự khóa ngăn ngừa một người sử dụng đọc hay thay đổi một hàng mà đang được thay đổi bởi một người sử dụng khác. Ví dụ, khi bạn cập nhật một hàng, một sự khóa hàng được đặt trên hàng đó ngăn ngừa người sử dụng khác cập nhật hàng đó cùng một thời điểm. Những kiểu khóa của SQL Server Máy chủ phục vụ SQL sử dụng nhiều kiểu khóa, Một số trong đó được trình bày trong Bảng 14.5. Bảng này trình bày những sự khóa trong thứ tự tăng dần của độ hạt khóa, nó tham chiếu tới kích thước của nguồn tài nguyên sẽ 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 Đượ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ố (EXT) 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 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 (DB) sử dụng đơn cho sự bảo trì. Những kiểu khóa của máy chủ phục vụ SQL
  15. 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 REPEATABLE READ hay SERIALIZABLE. Update (U) Chỉ rõ một giao dịch định sửa đổi một nguồn tài nguyên sử dụng một phát biểu INSERT, UPDATE, hay DELETE. Sự khóa phải được tăng tới một sự khóa dành riêng trước khi giao dịch thật sự thực hiện sự sửa đổi. Exclusive (X) Cho phép giao dịch sửa đổi nguồn tài nguyên sử dụng một phát biểu INSERT, UPDATE, hay DELETE . Không có giao dịch nào khác có thể đọc từ hay viết tới một nguồn tài nguyên mà trên đó một sự khóa dảnh riêng đã được đặt. Intent shared (IS) Chỉ rõ là giao dịch định đặt một khóa dùng chung trên một số nguồn tài nguyên tới một mức độ tốt hơn bên trong tài nguyên đó. Chẳng hạn, sự đặt một khóa IS trên một bảng chỉ báo rằng giao dịch định đặt một khóa dùng chung trên một số những trang hay những hàng bên trong bảng này. Không có giao dịch nào khác có thể đặt một khóa riêng trên một nguồn tài nguyên mà đã có một khóa IS trên nó. Intent exclusive Chỉ báo rằng giao dịch định đặt một khóa riêng trên một nguồn tài nguyên với một mức độ (IX) hạt tốt hơn. Không có giao dịch nào khác có thể đặt một khóa riêng trên một nguồn tài nguyên mà đã có một khóa IX trên nó. Shared with Chỉ báo rằng giao dịch định đọc tất cả những nguồn tài nguyên có một lượng độ hạt tốt hơn intent exclusive và sửa đổi một số tài nguyên đó. Chẳng hạn, việc đặt một khóa SIX trên một bảng cho biết (SIX) giao dịch định đọc tất cả những hàng trong bảng này và sửa đổi một số trong những hàng đó. Không có giao dịch nào khác có thể đặt một khóa riêng trên một nguồn tài nguyên mà đã có một khóa SIX trên nó. Schema Chỉ báo rằng một phát biểu ngôn ngữ định nghĩa dữ liệu (Data Definition Language _DDL) modification sẽ được thực hiện trên một nguồn tài nguyên mô hình, chẳng hạn, DROP TABLE. Không có (Sch-M) 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 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ư (Sch-S) 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.
  16. 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.' WHERE CustomerID = 'ALFKI' Việc này đặt một khóa dùng chung trên cơ sở dữ liệu Northwind và một số khóa trên bảng Customers, mà bạn có thể xem- sử dụng Enterprise Manager . Hình 14.3 cho thấy rằng những sự khóa này sử dụng những nút Locks/ Process ID của Enterprise Manager. SPID = 51 tương ứng với Query Analyzer nơi tôi đã chạy những câu lệnh T- SQLT trước đây. Như bạn có thể thấy từ hình này, một số khóa được đặt bởi những câu lệnh T-SQL trước . Hình 14.3: việc xem những khóa sử dụng nút Locks/ Process ID của Enterprise Manager. Để hồi nguyên giao dịch trước đây, thực hiện câu lệnh T-SQL sau đây: ROLLBACK TRANSACTION Để thả tự do cho những khóa, thực hiện câu lệnh T- SQLsau đây: COMMIT TRANSACTION Thông tin trong khung bên phải của Hình 14.3 trình bày những khóa, và thông tin này được chia vào trong những cột sau đây: Object Đối tượng sẽ bị khóa. Lock Type Kiểu khóa, tương ứng với một trong số những kiểu được chỉ ra trước đó trong Bảng 14.5. Mode chế độ khóa, tương ứng tới một trong số những chế độ khóa được chỉ ra trước đó trong Bảng 14.6. Tatus Tình trạng khóa, là GRANT (khóa đã được cấp phát thành công ), CNVT (khóa đã được chuyển
  17. đổi), hay WAIT(đợi khóa). 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. Hình 14.4: giao dịch trên phần trên đang khóa giao dịch trong phần dưới Để giao phó giao dịch trước và thả tự do cho những khóa cho giao dịch đầu tiên, bạn có thể thực hiện câu lệnh T- SQLsau đây:
  18. COMMIT TRANSACTION Điều này cho phép Cập nhật thứ hai (hiển thị ở phần dưới của Query Analyzer) lấy khóa thích hợp để Cập nhật hàng và tiến hành, như trình bày trong Hình 14.5 Hình 14.5: Một khi giao dịch ở phần trên đã được giao phó, sự Cập nhật ở phần dưới tiến hành. Gán Timeout cho khóa Theo mặc định, một câu lệnh SQL sẽ đợi đến vô tận để nhận một khóa. Bạn có thể thay đổi điều này bởi việc thực thi lệnh LOCK_TIMEOUT. Chẳng hạn, lệnh sau đây đặt khóa timeout tới 1 giây (1.000 mili-giây) SET LOCK_TIMEOUT 1000 Nếu một câu lệnh SQL phải đợi lâu hơn 1 giây, máy chủ phục vụ SQL sẽ trả về một lỗi và hủy bỏ câu lệnh SQL. Bạn cũng có thể thực thi lệnh SET LOCK_TIMEOUT trong mã C#. Chẳng hạn: mySqlCommand.CommandText = "SET LOCK_TIMEOUT 1000"; mySqlCommand.ExecuteNonQuery(); Bạn sẽ thấy sự sử dụng lệnh SET LOCK_TIMEOUT trong mục kế tiếp. 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
  19. 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 { public static void DisplayRows( SqlCommand mySqlCommand ) { mySqlCommand.CommandText = "SELECT CustomerID, CompanyName "+ "FROM Customers "+ "WHERE CustomerID IN ('ALFKI', 'J8COM')"; SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader(); while (mySqlDataReader.Read()) { Console.WriteLine("mySqlDataReader[\" CustomerID\"] = "+ mySqlDataReader["CustomerID"]); Console.WriteLine("mySqlDataReader[\" CompanyName\"] = "+ mySqlDataReader["CompanyName"]); } mySqlDataReader.Close(); } public static void Main() { // create and open two SqlConnection objects SqlConnection serConnection = new SqlConnection( "server=localhost;database=Northwind;uid=sa;pwd=sa" ); SqlConnection rcConnection = new SqlConnection( "server=localhost;database=Northwind;uid=sa;pwd=sa" ); 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
  20. 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 = rcConnection.CreateCommand(); readCommittedCommand.Transaction = readCommittedTrans; // set the lock timeout to 1 second using the // SET LOCK_TIMEOUT command readCommittedCommand.CommandText = "SET LOCK_TIMEOUT 1000"; readCommittedCommand.ExecuteNonQuery(); try { // insert a new row into the Customers table Console.WriteLine("Inserting new row into Customers table "+ "with CustomerID of J8COM"); readCommittedCommand.CommandText = "INSERT INTO Customers ("+ "CustomerID, CompanyName "+ ") VALUES ( " + " 'J8COM', 'J8 Company' "+ ")"; int numberOfRows = readCommittedCommand.ExecuteNonQuery(); Console.WriteLine("Number of rows inserted = "+ numberOfRows); // update the ALFKI row in the Customers table Console.WriteLine("Setting CompanyName to 'Widgets Inc.' for "+ "for row with CustomerID of ALFKI"); readCommittedCommand.CommandText = "UPDATE Customers "+ "SET CompanyName = 'Widgets Inc.' "+ "WHERE CustomerID = 'ALFKI'"; numberOfRows = readCommittedCommand.ExecuteNonQuery(); Console.WriteLine("Number of rows updated = "+ numberOfRows); // display the new rows and rollback the changes DisplayRows(readCommittedCommand);

CÓ THỂ BẠN MUỐN DOWNLOAD

Đồng bộ tài khoản