1. Trang chủ
  2. » Công Nghệ Thông Tin

Professional C# 2008 phần 5 pps

185 281 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 185
Dung lượng 2,47 MB

Nội dung

Part III: Base Class Libraries 680 successfully or neither of these actions should happen. If there is a failure when getting the book from stock, the credit card should not be charged. Transactions address such scenarios. The most common use of transactions is writing or updating data within the database. Transactions can also be performed when writing a message to a message queue, or writing data to a file or the registry. Multiple actions can be part of a single transaction. System.Messaging is discussed in Chapter 45 , “ Message Queuing. ” Figure 22 - 1 shows the main actors in a transaction. Transactions are managed and coordinated by the transaction manager, and a resource manager manages every resource that influences the outcome of the transaction. The transaction manager communicates with resource managers to define the outcome of the transaction. Transaction Manager Client Transaction Resource Manager Resource Manager Figure 22-1 Transaction Phases The timely phases of a transaction are the active , preparing , and committing phases: Active phase — During the active phase, the transaction is created. Resource managers that manage the transaction for resources can enlist with the transaction. Preparing phase — During the preparing phase, every resource manager can define the outcome of the transaction. This phase starts when the creator of the transaction sends a commit to end the transaction. The transaction manager sends a Prepare message to all resource managers. If the resource manager can produce the transaction outcome successfully, it sends a Prepared message to the transaction manager. Resource managers can abort the transaction if they fail to prepare by forcing a rollback with the transaction manager by sending a Rollback message. After the Prepared message is sent, the resource managers must guarantee to finish the work successfully in the committing phase. To make this possible, durable resource managers must write a log with the information from the prepared state, so that they can continue from there in case of, for example, a power failure between prepared and committing. Committing phase — The committing phase begins when all resource managers have prepared successfully. This is when the Prepared message is received from all resource managers. Then the ❑ ❑ ❑ c22.indd 680c22.indd 680 2/19/08 5:18:05 PM2/19/08 5:18:05 PM Chapter 22: Transactions 681 transaction manager can complete the work by sending a Commit message to all participants. The resource managers can now finish the work on the transaction and return a Committed message. ACID Properties A transaction has specific requirements; for example, a transaction must result in a valid state, even if the server has a power failure. The characteristics of transactions can be defined by the term ACID. ACID is a four - letter acronym for atomicity , consistency , isolation , and durability : Atomicity — Atomicity represents one unit of work. With a transaction, either the complete unit of work succeeds or nothing is changed. Consistency — The state before the transaction was started and after the transaction is completed must be valid. During the transaction, the state may have interim values. Isolation — Isolation means that transactions that happen concurrently are isolated from the state, which is changed during a transaction. Transaction A cannot see the interim state of transaction B until the transaction is completed. Durability — After the transaction is completed, it must be stored in a durable way. This means that if the power goes down or the server crashes, the state must be recovered at reboot. Not every transaction requires all four ACID properties. For example, a memory - based transaction (for example, writing an entry into a list) does not need to be durable. Also, a complete isolation from the outside is not always required, as we discuss later with transaction isolation levels. Database and Entity Classes The sample database CourseManagement that is used with the transactions in this chapter is defined by the structure from Figure 22 - 2 . The table Courses contains information about courses: course numbers and titles; for example, the course number 2124 with the title Programming C#. The table CourseDates contains the date of specific courses and is linked to the Courses table. The table Students contains information about persons attending a course. The table CourseAttendees is the link between Students and CourseDates . It defines which student is attending what course. You can download the database along with the source code for this chapter from the Wrox web site. ❑ ❑ ❑ ❑ Figure 22-2 c22.indd 681c22.indd 681 2/19/08 5:18:05 PM2/19/08 5:18:05 PM Part III: Base Class Libraries 682 The sample applications in this chapter use a library with entity and data access classes. The class Student contains properties to define a student; for example, FirstName , LastName , and Company : using System; namespace Wrox.ProCSharp.Transactions { [Serializable] public class Student { public Student() { } public Student(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName; } public string FirstName { get; set; } public string LastName { get; set; } public string Company { get; set; } public int Id { get; set; } public override string ToString() { return String.Format(“{0} {1}”, FirstName, LastName); } } } Adding student information to the database is done in the method AddStudent() of the class StudentData . Here, an ADO.NET connection is created to connect to the SQL Server database, the SqlCommand object defines the SQL statement, and the command is executed by invoking ExecuteNonQuery() : using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Transactions; namespace Wrox.ProCSharp.Transactions { public class StudentData { public void AddStudent(Student student) { SqlConnection connection = new SqlConnection( Properties.Settings.Default.CourseManagementConnectionString); connection.Open(); try { SqlCommand command = connection.CreateCommand(); command.CommandText = “INSERT INTO Students “ + “(FirstName, LastName, Company) VALUES “ + c22.indd 682c22.indd 682 2/19/08 5:18:06 PM2/19/08 5:18:06 PM Chapter 22: Transactions 683 “(@FirstName, @LastName, @Company)”; command.Parameters.AddWithValue(“@FirstName”, student.FirstName); command.Parameters.AddWithValue(“@LastName”, student.LastName); command.Parameters.AddWithValue(“@Company”, student.Company); command.ExecuteNonQuery(); } finally { connection.Close(); } } } } ADO.NET is covered in detail in Chapter 26 , “ Data Access ” Traditional Transactions Before System.Transaction was released, you could create transactions directly with ADO.NET, or you could do transactions with the help of components, attributes, and the COM+ runtime, which is covered in the namespace System.EnterpriseServices . To show you how the new transaction model compares to the traditional ways of working with transactions, we present a short look at how ADO.NET transactions and transactions with Enterprise Services are done. ADO.NET Transactions Let ’ s start with traditional ADO.NET transactions. If you don ’ t create transactions manually, there is a single transaction with every SQL statement. If multiple statements need to participate with the same transaction, however, you must create a transaction manually to achieve this. The following code segment shows how to work with ADO.NET transactions. The SqlConnection class defines the method BeginTransaction() , which returns an object of type SqlTransaction . This transaction object must then be associated with every command that participates with the transaction. To associate a command with a transaction, set the Transaction property of the SqlCommand class to the SqlTransaction instance. For the transaction to be successful, you must invoke the Commit() method of the SqlTransaction object. If there is an error, you have to invoke the Rollback() method, and every change is undone. You can check for an error with the help of a try / catch and do the rollback inside the catch. using System; using System.Data.SqlClient; using System.Diagnostics; namespace Wrox.ProCSharp.Transactions { public class CourseData { public void AddCourse(Course course) { SqlConnection connection = new SqlConnection( Properties.Settings.Default.CourseManagementConnectionString); SqlCommand courseCommand = connection.CreateCommand(); (continued) c22.indd 683c22.indd 683 2/19/08 5:18:06 PM2/19/08 5:18:06 PM Part III: Base Class Libraries 684 courseCommand.CommandText = “INSERT INTO Courses (Number, Title) VALUES (@Number, @Title)”; connection.Open(); SqlTransaction tx = connection.BeginTransaction(); try { courseCommand.Transaction = tx; courseCommand.Parameters.AddWithValue(“@Number”, course.Number); courseCommand.Parameters.AddWithValue(“@Title”, course.Title); courseCommand.ExecuteNonQuery(); tx.Commit(); } catch (Exception ex) { Trace.WriteLine(“Error: “ + ex.Message); tx.Rollback(); } finally { connection.Close(); } } } } If you have multiple commands that should run in the same transaction, every command must be associated with the transaction. Because the transaction is associated with a connection, every one of these commands must also be associated with the same connection instance. ADO.NET transactions do not support transactions across multiple connections; it is always a local transaction associated with one connection. When you create an object persistence model using multiple objects, for example, classes Course and CourseDate , which should be persisted inside one transaction, it gets very difficult using ADO.NET transactions. Here, it is necessary to pass the transaction to all of the objects participating in the same transaction. ADO.NET transactions are not distributed transactions. In ADO.NET transactions, it is difficult to have multiple objects working on the same transaction. System.EnterpriseServices With Enterprise Services you get a lot of services for free. One of them is automatic transactions. Using transactions with System.EnterpriseServices has the advantage that it is not necessary to deal with transactions explicitly; transactions are automatically created by the runtime. You just have to add the attribute [Transaction] with the transactional requirements to the class. The [AutoComplete] attribute marks the method to automatically set the status bit for the transaction: if the method succeeds, the success bit is set, so the transaction can commit. If an exception happens, the transaction is aborted. (continued) c22.indd 684c22.indd 684 2/19/08 5:18:06 PM2/19/08 5:18:06 PM Chapter 22: Transactions 685 using System; using System.Data.SqlClient; using System.EnterpriseServices; using System.Diagnostics; namespace Wrox.ProCSharp.Transactions { [Transaction(TransactionOption.Required)] public class CourseData : ServicedComponent { [AutoComplete] public void AddCourse(Course course) { SqlConnection connection = new SqlConnection( Properties.Settings.Default.CourseManagementConnectionString); SqlCommand courseCommand = connection.CreateCommand(); courseCommand.CommandText = “INSERT INTO Courses (Number, Title) VALUES (@Number, @Title)”; connection.Open(); try { courseCommand.Parameters.AddWithValue(“@Number”, course.Number); courseCommand.Parameters.AddWithValue(“@Title”, course.Title); courseCommand.ExecuteNonQuery(); } finally { connection.Close(); } } } } A big advantage of creating transactions with System.EnterpriseServices is that multiple objects can easily run within the same transaction, and transactions are automatically enlisted. The disadvantages are that it requires the COM+ hosting model, and the class using the features of this technology must be derived from the base class ServicedComponent . Enterprise Services and using COM+ transactional services are covered in Chapter 44 , “ Enterprise Services. ” System.Transactions The namespace System.Transactions has been available since .NET 2.0 and brings a new transaction programming model to .NET applications. Figure 22 - 3 shows a Visual Studio class diagram with the transaction classes, and their relationships, from the System.Transactions namespace: Transaction , CommittableTransaction , DependentTransaction , and SubordinateTransaction . Transaction is the base class of all transaction classes and defines properties, methods, and events available with all transaction classes. CommittableTransaction is the only transaction class that supports committing. This class has a Commit() method; all other transaction classes can do only a rollback. The class DependentTransaction is used with transactions that are dependent on another transaction. A dependent transaction can depend on a transaction created from the committable transaction. Then the dependent transaction adds to the outcome of the committable transaction whether or not it is successful. c22.indd 685c22.indd 685 2/19/08 5:18:07 PM2/19/08 5:18:07 PM Part III: Base Class Libraries 686 The class SubordinateTransaction is used in conjunction with the Distributed Transaction Coordinator (DTC). This class represents a transaction that is not a root transaction but can be managed by the DTC. Figure 22-3 Transaction Class Members Description Current The property Current is a static property without the need to have an instance. Transaction.Current returns an ambient transaction if one exists. Ambient transactions are discussed later in this chapter. IsolationLevel The IsolationLevel property returns an object of type IsolationLevel. IsolationLevel is an enumeration that defines what access other transactions have to the interim results of the transaction. This affects the I of ACID; not all transactions are isolated. TransactionInformation The TransactionInformation property returns a TransactionInformation object. TransactionInformation gives you information about the current state of the transaction, the time when the transaction was created, and transaction identifiers. EnlistVolatile() EnlistDurable() EnlistPromotableSinglePhase() With the enlist methods EnlistVolatile(), EnlistDurable(), and EnlistPromotableSinglePhase(), you can enlist custom resource managers that participate with the transaction. The following table describes the properties and methods of the Transaction class. c22.indd 686c22.indd 686 2/19/08 5:18:07 PM2/19/08 5:18:07 PM Chapter 22: Transactions 687 Transaction Class Members Description Rollback() With the Rollback() method, you can abort a transaction and undo everything to set all results to the state before the transaction. DependentClone() With the DependentClone() method, you can create a transaction that depends on the current transaction. TransactionCompleted TransactionCompleted is an event that is fired when the transaction is completed — either successfully or unsuccess- fully. With an event handler object of type Transaction CompletedEventHandler , you get access to the Transaction object and can read its status. For demonstrating the features of System.Transaction , the class Utilities inside a separate assembly offers some static methods. The method AbortTx() returns true or false depending on the input from the user. The method DisplayTransactionInformation() gets a TransactionInformation object as parameter and displays all the information from the transaction: creation time, status, local, and distributed identifiers: public static class Utilities { public static bool AbortTx() { Console.Write(“Abort the Transaction (y/n)?”); return Console.ReadLine() == “y”; } public static void DisplayTransactionInformation(string title, TransactionInformation ti) { if (ti != null) { Console.WriteLine(title); Console.WriteLine(“Creation Time: {0:T}”, ti.CreationTime); Console.WriteLine(“Status: {0}”, ti.Status); Console.WriteLine(“Local ID: {0}”, ti.LocalIdentifier); Console.WriteLine(“Distributed ID: {0}”, ti.DistributedIdentifier); Console.WriteLine(); } } } Committable Transactions The Transaction class cannot be committed programmatically; it does not have a method to commit the transaction. The base class Transaction just supports aborting the transaction. The only transaction class that supports a commit is the class CommittableTransaction . c22.indd 687c22.indd 687 2/19/08 5:18:08 PM2/19/08 5:18:08 PM Part III: Base Class Libraries 688 With ADO.NET, a transaction can be enlisted with the connection. To make this possible, an AddStudent() method is added to the class StudentData that accepts a System.Transactions. Transaction object as second parameter. The object tx is enlisted with the connection by calling the method EnlistTransaction of the SqlConnection class. This way, the ADO.NET connection is associated with the transaction. public void AddStudent(Student student, Transaction tx) { SqlConnection connection = new SqlConnection( Properties.Settings.Default.CourseManagementConnectionString); connection.Open(); try { if (tx != null) connection.EnlistTransaction(tx); SqlCommand command = connection.CreateCommand(); command.CommandText = “INSERT INTO Students (FirstName, “ + “LastName, Company)” + “VALUES (@FirstName, @LastName, @Company)”; command.Parameters.AddWithValue(“@FirstName”, student.FirstName); command.Parameters.AddWithValue(“@LastName”, student.LastName); command.Parameters.AddWithValue(“@Company”, student.Company); command.ExecuteNonQuery(); } finally { connection.Close(); } } In the Main() method of the console application CommittableTransaction , first a transaction of type CommittableTransaction is created, and information is shown on the console. Then a Student object is created, and this object is written to the database from the AddStudent() method. If you verify the record in the database from outside of the transaction, you cannot see the student added until the transaction is completed. In case the transaction fails, there is a rollback, and the student is not written to the database. After the AddStudent() method is invoked, the helper method Utilities.AbortTx() is called to ask if the transaction should be aborted. If the user aborts, an exception of type ApplicationException is thrown and, in the catch block, a rollback with the transaction is done by calling the method Rollback() of the Transaction class. The record is not written to the database. If the user does not abort, the Commit() method commits the transaction, and the final state of the transaction is committed. static void Main() { CommittableTransaction tx = new CommittableTransaction(); Utilities.DisplayTransactionInformation(“TX created”, tx.TransactionInformation); try { Student s1 = new Student(); c22.indd 688c22.indd 688 2/19/08 5:18:08 PM2/19/08 5:18:08 PM Chapter 22: Transactions 689 s1.FirstName = “Neno”; s1.LastName = “Loye”; s1.Company = “thinktecture”; StudentData db = new StudentData(); db.AddStudent(s1, tx); if (Utilities.AbortTx()) { throw new ApplicationException(“transaction abort”); } tx.Commit(); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(); tx.Rollback(); } Utilities.DisplayTransactionInformation(“TX completed”, tx.TransactionInformation); } Here, you can see the output of the application where the transaction is active and has a local identifier. The output of the application that follows shows the result with the user choice to abort the transaction. After the transaction is finished, you can see the aborted state. TX created Creation Time: 7:30:49 PM Status: Active Local ID: bdcf1cdc-a67e-4ccc-9a5c-cbdfe0fe9177:1 Distributed ID: 00000000-0000-0000-0000-000000000000 Abort the Transaction (y/n)? y Transaction abort TX completed Creation Time: 7:30:49 PM Status: Aborted Local ID: bdcf1cdc-a67e-4ccc-9a5c-cbdfe0fe9177:1 Distributed ID: 00000000-0000-0000-0000-000000000000 Press any key to continue With the second output of the application that you can see here, the transaction is not aborted by the user. The transaction has the status committed, and the data is written to the database. TX Created Creation Time: 7:33:04 PM Status: Active Local ID: 708bda71-fa24-46a9-86b4-18b83120f6af:1 (continued) c22.indd 689c22.indd 689 2/19/08 5:18:08 PM2/19/08 5:18:08 PM [...]... 700 2/19/08 5: 18:12 PM Chapter 22: Transactions Main thread TX Creation Time: 23:00 :57 Status: Active Local ID: 2fb1b54d-61f5-4d4e-a55e-f4a9e04778be:1 Distributed ID: 00000000-0000-0000-0000-000000000000 Thread TX Creation Time: 23:00 :57 Status: Active Local ID: 2fb1b54d-61f5-4d4e-a55e-f4a9e04778be:1 Distributed ID: 00000000-0000-0000-0000-000000000000 TX completed Creation Time: 23:00 :57 Status: Committed... 11:01:09 PM Status: Active Local ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Inner Transaction Scope Creation Time: 11:01:09 PM Status: Active Local ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:2 Distributed ID: 00000000-0000-0000-0000-0000000000 TX completed Creation Time: 11:01:09 PM Status: Committed Local ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:2 Distributed... Distributed ID: 00000000-0000-0000-0000-000000000000 TX completed Creation Time: 23:00 :57 Status: Committed Local ID: 2fb1b54d-61f5-4d4e-a55e-f4a9e04778be:1 Distributed ID: 00000000-0000-0000-0000-000000000000 TX completed Creation Time: 23:00 :57 Status: Committed Local ID: 2fb1b54d-61f5-4d4e-a55e-f4a9e04778be:1 Distributed ID: 00000000-0000-0000-0000-000000000000 Isolation Level At the beginning of this chapter,... Creation Time: 8: 35: 25 PM Status: Active Local ID: 50 126e07-cd28-4e0f-a21f-a81a8e14a1a8:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Abort the Transaction (y/n)? n Dependent Transaction Creation Time: 8: 35: 25 PM Status: Active Local ID: 50 126e07-cd28-4e0f-a21f-a81a8e14a1a8:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Dependent TX Complete Root TX finished Creation Time: 8: 35: 25 PM Status:... distributed identifier is associated with the transaction TX created Creation Time: 7 :56 :24 PM Status: Active Local ID: 0d2f5ada-32aa-40eb-b9d7-cc6aa9a2a 554 :1 Distributed ID: 00000000-0000-0000-0000-0000000000 2nd connection enlisted Creation Time: 7 :56 :24 PM Status: Active Local ID: 0d2f5ada-32aa-40eb-b9d7-cc6aa9a2a 554 :1 Distributed ID: 70762617-2ee8-4d23-aa87-6ac8c1418bdfd Abort the Transaction (y/n)?... handler to display the finished transaction state Ambient TX created Creation Time: 9 :55 :40 PM Status: Active Local ID: a06df6fb-7266-435e-b90e-f024f1d6966e:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Abort the Transaction (y/n)? n TX completed Creation Time: 9 :55 :40 PM Status: Committed Local ID: a06df6fb-7266-435e-b90e-f024f1d6966e:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Press any... TX Creation Time: 21:41: 25 Status: Active Local ID: f1e736ae-84ab- 454 0-b71e-3de272ffc476:1 Distributed ID: 00000000-0000-0000-0000-000000000000 TX completed Creation Time: 21:41: 25 Status: Committed Local ID: f1e736ae-84ab- 454 0-b71e-3de272ffc476:1 Distributed ID: 00000000-0000-0000-0000-000000000000 Thread TX Creation Time: 21:41: 25 Status: Active Local ID: f1e736ae-84ab- 454 0-b71e-3de272ffc476:2 Distributed... finished Creation Time: 8: 35: 25 PM Status: Committed Local ID: 50 126e07-cd28-4e0f-a21f-a81a8e14a1a8:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Creation Time: 8: 35: 25 PM Status: Committed Local ID: 50 126e07-cd28-4e0f-a21f-a81a8e14a1a8:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Press any key to continue 693 c22.indd 693 2/19/08 5: 18:09 PM Part III: Base Class Libraries Ambient Transactions... rows For example, UPDATE Addresses SET Zip=4711 WHERE (Zip=23 15) updates the ZIP code of all records from 23 15 to 4711 After doing the update, there may still be records with a ZIP code of 23 15 if another user added a new record with ZIP 23 15 while the update was running You can avoid this by doing a range lock 701 c22.indd 701 2/19/08 5: 18:12 PM Part III: Base Class Libraries When defining the isolation... using System; using System.Runtime.InteropServices; namespace Wrox.ProCSharp.Transactions { [ComImport] [Guid(“79427A2B-F8 95- 40e0-BE79-B57DC82ED231”)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IKernelTransaction (continued) 711 c22.indd 711 2/19/08 5: 18: 15 PM Part III: Base Class Libraries (continued) { void GetHandle(out SafeTransactionHandle ktmHandle); } } Finally, the . ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Inner Transaction Scope Creation Time: 11:01:09 PM Status: Active Local ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:2 Distributed. Committed Local ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:2 Distributed ID: 00000000-0000-0000-0000-0000000000 TX completed Creation Time: 11:01:09 PM Status: Committed Local ID: 54 ac1276-5c2d-4 159 -84ab-36b0217c9c84:1 Distributed. 9 :55 :40 PM Status: Active Local ID: a06df6fb-7266-435e-b90e-f024f1d6966e:1 Distributed ID: 00000000-0000-0000-0000-0000000000 Abort the Transaction (y/n)? n TX completed Creation Time: 9 :55 :40

Ngày đăng: 12/08/2014, 23:23

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN